如何在Python中使用线程?
我试图理解Python中的线程。我已经看过文档和示例,但坦率地说,许多示例过于复杂,我无法理解它们。
如何清楚地显示为多线程划分的任务?
我试图理解Python中的线程。我已经看过文档和示例,但坦率地说,许多示例过于复杂,我无法理解它们。
如何清楚地显示为多线程划分的任务?
自从2010年提出这个问题以来,关于如何用Python进行简单的多线程处理,以及地图和池,已经有了真正的简化。
下面的代码来自一篇文章/博客文章,你绝对应该检查出来(没有隶属关系) - 一行并行性:日常线程任务的更好模型。我将总结如下 - 它最终只有几行代码:
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))
描述
Map是一个很酷的小函数,也是将并行性轻松注入Python代码的关键。对于那些不熟悉的人来说,map是从Lisp等函数式语言中提升出来的。它是一个在序列上映射另一个函数的函数。
Map 为我们处理序列的迭代,应用函数,并将所有结果存储在末尾的便捷列表中。
实现
映射函数的并行版本由两个库提供:multiprocessing,以及它鲜为人知但同样出色的步骤child:multiprocessing.dummy。
multiprocessing.dummy
与多处理模块完全相同,但使用线程代替(一个重要的区别 - 对 CPU 密集型任务使用多个进程;用于(和期间)I/O 的线程):
multiprocessing.dummy 复制了多处理的 API,但只不过是线程模块的包装器。
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/',
]
# Make the Pool of workers
pool = ThreadPool(4)
# Open the URLs in their own threads
# and return the results
results = pool.map(urllib2.urlopen, urls)
# Close the pool and wait for the work to finish
pool.close()
pool.join()
计时结果如下:
Single thread: 14.4 seconds
4 Pool: 3.1 seconds
8 Pool: 1.4 seconds
13 Pool: 1.3 seconds
传递多个参数(仅在 Python 3.3 及更高版本中如此工作):
传递多个数组:
results = pool.starmap(function, zip(list_a, list_b))
或者传递一个常量和一个数组:
results = pool.starmap(function, zip(itertools.repeat(constant), list_a))
如果您使用的是早期版本的Python,则可以通过此解决方法传递多个参数)。
(感谢user136036的有用评论。
下面是一个简单的示例:您需要尝试几个备用 URL,并返回第一个 URL 的内容以进行响应。
import Queue
import threading
import urllib2
# Called by each thread
def get_url(q, url):
q.put(urllib2.urlopen(url).read())
theurls = ["http://google.com", "http://yahoo.com"]
q = Queue.Queue()
for u in theurls:
t = threading.Thread(target=get_url, args = (q,u))
t.daemon = True
t.start()
s = q.get()
print s
这是线程用作简单优化的情况:每个子线程都在等待URL解析和响应,将其内容放在队列上;每个线程都是一个守护进程(如果主线程结束,则不会保持进程的运行 - 这比不常见);主线程启动所有子线程,在队列上执行 a,直到其中一个子线程完成 ,然后发出结果并终止(这会删除可能仍在运行的任何子线程,因为它们是守护进程线程)。get
put
在Python中正确使用线程总是连接到I / O操作(因为CPython无论如何都不使用多个内核来运行CPU密集型任务,因此线程化的唯一原因不是在等待某些I / O时阻塞进程)。顺便说一句,队列几乎总是将工作外包给线程和/或收集工作结果的最佳方式,并且它们本质上是线程安全的,因此它们使您不必担心锁,条件,事件,信号量和其他线程间协调/通信概念。