1.使用concurrent.futures
可通过concurrent.futures中的ThreadPoolExecutor、 ProcessPoolExecutor分别实现多线程、多进程并行任务。以具体例子来说话:
假设程序用来获取一个数列中各元素是否为素数。
PRIMES = [112272535095293,112582705942171,
112272535095293,115280095190773,
115797848077099,1099726899285419]
def is_prime(n):
if n < 2:
return False
if n == 2:
return True
if n % 2 == 0:
return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:
return False
return True
1.1 不使用多线程/多进程
start = time.time()
results = list(map(is_prime, PRIMES))
end = time.time()
print ('Took %.3f seconds.' % (end - start))
结果打印输出:“Took 4.788 seconds.”
1.2 使用多线程
def main():
start = time.time()
pool =concurrent.futures.ThreadPoolExecutor(max_workers=2)
results = list(pool.map(is_prime, PRIMES))
end = time.time()
print ('Took %.3f seconds.' % (end - start))
if __name__ == '__main__':
main()
结果打印输出:“Took 4.958 seconds."
1.3 使用多进程
def main():
start = time.time()
pool = ProcessPoolExecutor(max_workers=2)
results = list(pool.map(is_prime, PRIMES))
end = time.time()
print ('Took %.3f seconds.' % (end - start))
if __name__ == '__main__':
main()
结果打印输出:“Took 3.781 seconds.”
容易发现使用多线程竟然比使用单线程还要慢一点。
这是因为GIL(Global Interpreter Lock)在python处理CPU密集型运算线程时,并不会增强CPU的并发处理能力。
1.3.1 关于GIL(global interpreter lock,全局解释器锁)
在
python中文术语对照表
中GIL给出的解释为:
CPython 解释器所采用的一种机制,它确保同一时刻只有一个线程在执行 Python bytecode。此机制通过设置对象模型(包括 dict 等重要内置类型)针对并发访问的隐式安全简化了 CPython 实现。给整个解释器加锁使得解释器多线程运行更方便,其代价则是牺牲了在多处理器上的并行性 。
其他解释也可参考
参考文件4
。
2.python threading模块
Python3 通threading 模块提供了对多线程的支持。
同样求解上述素数问题,把list元素平分为两份,供生成的两个进程使用。
PRIME1 = [
112272535095293,
112582705942171,
112272535095293]
PRIME2=[
115280095190773,
115797848077099,
1099726899285419]
def is_prime(n):
if n < 2:return False
if n == 2:return True
if n % 2 == 0:return False
sqrt_n = int(math.floor(math.sqrt(n)))
for i in range(3, sqrt_n + 1, 2):
if n % i == 0:return False
return True
import threading
import time
import math
class myThread (threading.Thread):
def __init__(self, threadID, name,prime):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.prime = prime
def run(self):
for item in self.prime:
is_prime(item)
start = time.time()
# 创建新线程
thread1 = myThread(1, "Thread-1",PRIME1)
thread2 = myThread(2, "Thread-2",PRIME2)
# 开启新线程
thread1.start()
thread2.start()
thread1.join()
thread2.join()
#results = list(map(gcd, numbers))
end = time.time()
print ('Took %.3f seconds.' % (end - start))
打印结果:
Took 4.871 seconds.
3.python multiprocessing 模块
multiprocessing模块的
Pool 对象
提供了一种方便的方法,可以跨多个输入值并行化函数的执行,跨进程分配输入数据(数据并行),而 threading 模块中没有类似物的API。
from multiprocessing import Pool
if __name__ == '__main__':
start = time.time()
pool=Pool(2)
results = list(pool.map(is_prime, PRIMES))
end = time.time()
print ('Took %.3f seconds.' % (end - start))