Python中使用线程的一些可行方法

受益于在此的讨论:http://stackoverflow.com/questions/2846653/how-to-use-threading-in-python

另外一篇了解Python内线程机制的交好blog: https://jeffknupp.com/blog/2012/03/31/pythons-hardest-problem/

1、使用 threading module:

适用范围:

适用于建立那些与I/O操作相关的操作线程。

因为CPython并不真正在多个core上并发执行多个CPU密集型(CPU-bound)的线程。使用threading.Thread class来建立的线程在真正执行时,受限于Python 解释器的全局锁,只能串行地在CPU上进行执行即使我们的CPU上有多个core充分支持多线程并发执行。但是对于某些包含有重I/O操作的进程中,我们可以使用threading来建立线程,然后由它来单独等待i/o操作(网络数据或disk数据)完成,此时将cpu资源释放出来交由主程序线程继续执行,因此整体起到了让主程序线程不被i/o阻塞的作用。

应用实例:

实例一:

import Queue

import threading

import urllib2

# 每个新建线程所调用的执行函数

def get_url(q, url):

q.put(urllib2.urlopen(url).read())

theurls = ["http://google.com", "http://yahoo.com"]

q = Queue.Queue() #Queue在内部实现的时候就是线程安全的,所以在使用它的时候不需考虑锁、条件变量、事件及信息量等多线程间执行协调因子

for u in theurls:

t = threading.Thread(target=get_url, args = (q,u))

# 将每个新建的线程设为daemon模式,这样当主线程结束后,新建的子线程可继续执行

t.daemon = True #

t.start()

s = q.get()

print s

2、真正的并发执行-使用multiprocessing:

适用范围:

适用于需要fork出多个进程,然后执行真正的多core CPU之上并发执行的程序。

multiprocessing module可以fork出多个真正并发执行的进程。由于全局解释器锁的原因,使用threading模块只能交替执行其建立的多个线程,而这只有在有i/o操作阻塞需要绕过的时候才能发挥较好的作用。。

应用实例:

实例一:

from multiprocessing import Process

def f(name):

print 'hello', name

if __name__ == '__main__':

p = Process(target=f, args=('bob',))

p.start()

p.join()

这个小程序创建了一个进程,让它运行起来。主程序在将它启动起来后,又使用join方法等待它执行结束退出,然后回收它。此后主进程才会退出,程序执行完成。如果我们不在程序的最后使用join来等待子进程执行结束,那么主进程退出后,子进程有可能尚未退出,这会导致它成为一个僵尸进程,资源无法得到有效回收。

3、使用multiprocessing.dummy中的Pool或者直接使用multiprocessing.Pool(关于multiprocessing.dummy的区别,可由官方文档上的说明而知。‘multiprocessing.dummy replicates the API of multiprocessing but is no more than a wrapper around the threading module.’)

通过使用map与Pool来生成多个具有相同目标函数的并发线程。其中map是函数式编程的一个常用函数,另一个是reduce。

实例一:

from multiprocessing.dummy import Pool as ThreadPool

pool = ThreadPool(4)

results = pool.map(my_function, my_array)

它是由如下单线程程序改进而得的多线程程序。

results = []

for item in my_array:

results.append(my_function(item))

实例二:

import urllib2

from multiprocessing.dummy import Pool as ThreadPool

urls = [

'http://www.python.org',

'http://www.python.org/about/',

'http://www.onlamp.com/pub/a/python/2003/04/17/metaclasses.html',

'http://www.python.org/doc/',

'http://www.python.org/download/',

'http://www.python.org/getit/',

'http://www.python.org/community/',

'https://wiki.python.org/moin/',

]

# 在各个线程内部调用同一个目标运行函数'urllib2.urlopen',但是传入不同的参数,进而在这些线程中返回不同的值

with Pool(4) as pool:

results = pool.map(urllib2.urlopen, urls)

#当然也可使用多个数组作为参数,如下所示

results = pool.starmap(function, zip(list_a, list_b))

#或者也可以向下面这样使用一个常量与数组作为参数,如下所示

results = pool.starmap(function, zip(itertools.repeat(constant), list_a))

4、结合threading, multiprocessing, subprocess进行的多进程并发

利用threading来建立多个交叉执行的线程,然后在每个线程中执行由subprocess直接启动的可在shell下执行的进程。

import Queue

import threading

import multiprocessing

import subprocess

q = Queue.Queue()

for i in range(30): #将我们要执行的30个任务放入队列当中

q.put(i)

def worker():

while True:

item = q.get()

#执行一个任务,调用shell程序,在下面执行我们的task,然后等待它结束返回

subprocess.call("echo "+str(item), shell=True)

q.task_done()

cpus=multiprocessing.cpu_count() #获得我们系统中所具有的可执行cpu核的数目

print("Creating %d threads" % cpus)

for i in range(cpus):

t = threading.Thread(target=worker)

t.daemon = True

t.start()

q.join() #队列阻塞直到所有task被执行完毕

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 本文是笔者学习廖雪峰Python3教程的笔记,在此感谢廖老师的教程让我们这些初学者能够一步一步的进行下去.如果读者...
    相关函数阅读 5,572评论 1 8
  • 1.进程 1.1多线程的引入 现实生活中 有很多的场景中的事情是同时进行的,比如开车的时候手和脚共同来驾驶汽车,再...
    TENG书阅读 581评论 0 0
  • 多任务可以由多进程完成,也可以由一个进程内的多线程完成。我们前面提到了进程是由若干线程组成的,一个进程至少有一个线...
    壁花烧年阅读 850评论 0 0
  • 目录 一、开启线程的两种方式 在python中开启线程要导入threading,它与开启进程所需要导入的模块mul...
    CaiGuangyin阅读 2,435评论 1 16
  • 个人笔记,方便自己查阅使用 Py.LangSpec.Contents Refs Built-in Closure ...
    freenik阅读 67,799评论 0 5