python 多线程/多进程 concurrent.futures/threading/multiprocessing

python 多线程/多进程

  • 1.使用concurrent.futures
    • 1.1 不使用多线程/多进程
    • 1.2 使用多线程
    • 1.3 使用多进程
      • 1.3.1 关于GIL(global interpreter lock,全局解释器锁)
  • 2.python threading模块
  • 3.python multiprocessing 模块
  • 参考文献

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))        

参考文献

[1] Python3 多线程
[2] python concurrent.futures
[3] concurrent.futures — 启动并行任务
[4] 简书 GIL

你可能感兴趣的:(python,从安装到入门,实操,多线程,python,多进程,thread)