如何在Python中使用线程?

我想了解Python中的线程。 我已经看过文档和示例,但坦率地说,很多示例都非常复杂,我无法理解它们。

你如何清楚地显示被划分为多线程的任务?


自从2010年提出这个问题以来,已经真正简化了如何用mappool进行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代码的关键。 对于那些不熟悉的人来说,地图可以从Lisp等功能语言中解脱出来。 它是一个将另一个函数映射到一个序列上的函数。

Map处理对我们的迭代,应用函数,并将所有结果存储在最后的便捷列表中。

在这里输入图像描述


履行

并行版本的map函数由两个库提供:多处理,以及其已知但同样非常棒的步骤子:multiprocessing.dummy。

multiprocessing.dummy与多处理模块完全相同,但使用线程代替(一个重要的区别 - 对CPU密集型任务使用多个进程;对于(和在)IO中使用线程):

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解析和响应,以便将其内容放入队列; 每个线程都是一个守护进程(如果主线程结束,将不会保留进程 - 这比通常更常见); 主线程启动所有的子线程,做一个get队列等待,直到其中一人已经做了put ,然后发出的结果,并终止(这需要下可能仍在运行的所有子线程,因为他们是守护线程)。

在Python中正确使用线程总是与I / O操作相连接(因为CPython无论如何都不使用多个核心来运行CPU绑定任务,线程的唯一原因并不是阻塞进程,而是等待某些I / O )。 顺便提一下,队列几乎总是将工作排除在外并且/或者收集工作结果的最佳方式,而且它们本质上是线程安全的,因此它们可以让您免于担心锁,条件,事件,信号量以及其他互操作性问题,线程协调/通信概念。


注意:对于Python中的实际并行化,您应该使用多处理模块来并行执行多个进程(由于全局解释器锁定,Python线程提供了交错,但实际上是串行执行的,而不是并行执行的,交错I / O操作)。

然而,如果你只是在寻找交错(或者正在做I / O操作,尽管全局解释器锁定可以并行化),那么线程模块就是开始的地方。 作为一个非常简单的例子,让我们考虑通过并行求和子范围来求和大范围的问题:

import threading

class SummingThread(threading.Thread):
     def __init__(self,low,high):
         super(SummingThread, self).__init__()
         self.low=low
         self.high=high
         self.total=0

     def run(self):
         for i in range(self.low,self.high):
             self.total+=i


thread1 = SummingThread(0,500000)
thread2 = SummingThread(500000,1000000)
thread1.start() # This actually causes the thread to run
thread2.start()
thread1.join()  # This waits until the thread has completed
thread2.join()  
# At this point, both threads have completed
result = thread1.total + thread2.total
print result

请注意,以上是一个非常愚蠢的例子,因为它绝对没有I / O,并且由于全局解释器锁定而将在CPython中以串行方式执行,尽管它们是交错的(伴随着上下文切换的额外开销)。

链接地址: http://www.djcxy.com/p/40331.html

上一篇: How to use threading in Python?

下一篇: Profiling C++ multi