Python在程序并行化方面多少有些声名狼藉。撇开技术上的问题,例如线程的实现和吉尔,我觉得错误的教学指导才是主要问题。
常见的经典Python多线程,多进程教程多显得偏“重“。而且往往隔靴搔痒,没有深入探讨日常工作中最有用的内容。
简单搜索下“Python多线程教程“,不难发现几乎所有的教程都给出涉及类和队列的例子:
<前> <代码>导入操作系统进口公益诉讼
从多处理导入池
从公益诉讼导入图片
大小
=(75、75)
SAVE_DIRECTORY=& # 39;拇指# 39;
def get_image_paths(文件夹):
,返回(os.path。加入(文件夹,f)
,,,,,,在os.listdir f(文件夹)
,,,,,,如果& # 39;jpeg # 39;在f)
def create_thumbnail(文件名):
,,im=Image.open(文件名)
,即时通讯。缩略图(尺寸、Image.ANTIALIAS)
,,基础、?os.path.split(文件名)
,save_path=os.path。加入(基地,SAVE_DIRECTORY、帧)
,,im.save (save_path)
if __name__==& # 39; __main__ # 39;:
,=os.path.abspath,文件夹(
,,,,& # 39;_18_2013_r000_iqm_big_sur_mon__e10d1958e7b766c3e840& # 39; 11日)
,os.mkdir (os.path。加入(文件夹,SAVE_DIRECTORY))
,,图像=get_image_paths(文件夹)
,池,池=()
,池。地图(creat_thumbnail、图片)
,,pool.close ()
,代码,pool.join () >
哈,看起来有些像Java不是吗?
我并不是说使用生产者/消费者模型处理多线程/多进程任务是错误的(事实上,这一模型自有其用武之地)。只是,处理日常脚本任务时我们可以使用更有效率的模型。
首先,你需要一个样板类,,
其次,你需要一个队列来传递对象,,
而且,你还需要在通道两端都构建相应的方法来协助其工作(如果需想要进行双向通信或是保存结果还需要再引入一个队列)。
按照这一思路,你现在需要一个工人线程的线程池。下面是一篇IBM经典教程中的例子,在进行网页检索时通过多线程进行加速。
<前> <代码> # Example2.py& # 39; & # 39; & # 39;
一个更实际的线程池的例子
& # 39; & # 39; & # 39;
导入时间
进口线程
进口队列 进口urllib2
类消费者(threading.Thread):
,队列,def __init__(自我):
,,,,threading.Thread.__init__(自我)
,,,自我。_queue=队列
,,def运行(自我):
,,,,而真正的:
,,,,,,内容=self._queue.get ()
,,,,,内容,如果isinstance (str)和内容==& # 39;退出# 39;:
,,,,,,,,打破
,,,,,,反应=urllib2.urlopen(内容)
,,,,打印& # 39;再见是的! & # 39;
def生产商():
,,url=[
,,,,& # 39;http://www.python.org& # 39; & # 39; http://www.yahoo.com& # 39;
,,,,& # 39;http://www.scala.org& # 39; & # 39; http://www.google.com& # 39;
,,,,#等。
,,)
,,队列=Queue.Queue ()
,,worker_threads=build_worker_pool(队列,4)
,,start_time=time.time ()
,# url添加到流程
,的网址,网址:
,,,,queue.put (url),
,#添加毒pillv
,,工人在worker_threads:
,,,,queue.put(& # 39;退出# 39;)
,,工人在worker_threads:
,,,,worker.join ()
,,打印& # 39;完成了!时间:{}& # 39;.format (time.time () - start_time)
def build_worker_pool(队列、大小):
,,工人=[]
,,_的范围(大小):
,,,,工人=消费者(队列)
,,,,worker.start ()
,,,,workers.append(工人)
,工人,返回
if __name__==& # 39; __main__ # 39;:
,,生产者()代码>
这段代码能正确的运行,但仔细看看我们需要做些什么:构造不同的方法,追踪一系列的线程,还有为了解决恼人的死锁问题,我们需要进行一系列的加入操作。这还只是开始……
至此我们回顾了经典的多线程教程,多少有些空洞不是吗?样板化而且易出的错,这样事倍功半的风格显然不那么适合日常使用,好在我们还有更好的方法。
地图这一小巧精致的函数是简捷实现Python程序并行化的关键. map源于Lisp这类函数式编程语言。它可以通过一个序列实现两个函数之间的映射。