python并发的实现
python可以通过调用子进程和子线程两种方式实现并行。由于python的多线程只能在一个CPU核心上工作,对于多核CPU会大大浪费资源,所以都采用多进程实现pyhon并发。
python并发的实现原理
python 支持三种启动进程的方法。这些 启动方法 有
spawn
父进程会启动一个全新的 python 解释器进程。 子进程将只继承那些运行进程对象的 run() 方法所必需的资源。 特别地,来自父进程的非必需文件描述符和句柄将不会被继承。 使用此方法启动进程相比使用 fork 或 forkserver 要慢上许多。
可在Unix和Windows上使用。 Windows上的默认设置。
fork
父进程使用 os.fork() 来产生 Python 解释器分叉。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程是棘手的。
只存在于Unix。Unix中的默认值。
forkserver
程序启动并选择* forkserver * 启动方法时,将启动服务器进程。从那时起,每当需要一个新进程时,父进程就会连接到服务器并请求它分叉一个新进程。分叉服务器进程是单线程的,因此使用 os.fork() 是安全的。没有不必要的资源被继承。
可在Unix平台上使用,支持通过Unix管道传递文件描述符。
python进程并发的常用方式
python进程并发通常采用进程池(pool)的方式调用
python并行举例(适用python2.7)
apply_async方法调用
此种方法调用灵活,可以传递多个参数,还以调用回调函数
使用方法:
apply_async(func[, args[, kwds[, callback]]])?
apply() 方法的一个变种,返回一个结果对象。这个对象可以使用get()方法取出结果
举例
#!/usr/bin/env python
from multiprocessing import Pool
import os
import time
def f(x):
time.sleep(5)
print(os.getpid())
print(os.getppid())
return 1
pool = Pool(3)
result = []
for x in range(3):
result.append(pool.apply_async(f,[x,]))
pool.close()
pool.join()
for i in result:
print(i.get())
map方法
这种方式与python的map方法一样,优点是效率高,缺点是只能有一个参数传入,不能回调,使用不灵活
使用方法:
map(func, iterable[, chunksize])?
举例:
#!/usr/bin/python env
from multiprocessing import Pool, TimeoutError
import time
import os
def f(x):
return x*x
if __name__ == '__main__':
pool = Pool(processes=4) # start 4 worker processes
# print "[0, 1, 4,..., 81]"
print pool.map(f, range(10))
python并行的注意事项
子程序异常后,使用get()方法取值将报错.
参考:https://docs.python.org/zh-cn/2.7/library/multiprocessing.html#process-and-exceptions
参考:https://docs.python.org/zh-cn/3/library/multiprocessing.html