多进程multiprocessing
PACKAGE CONTENTS
connection
dummy (package)
forking
heap
managers
pool
process
queues
reduction
sharedctypes
synchronize
util
the class frequently-used of the module:
1、Process
Process 类用来描述一个进程对象。创建子进程的时候,只需要传入一个执行函数和函数的参数即可完成 Process 示例的创建。
star() 方法启动进程,
join() 方法实现进程间的同步,等待所有进程退出。
close() 用来阻止多余的进程涌入进程池 Pool 造成进程阻塞。
class Process(__builtin__.object) | Process objects represent activity that is run in a separate process | | The class is analagous to `threading.Thread` | | Methods defined here: | | __init__(self, group=None, target=None, name=None, args=(), kwargs={}) | | __repr__(self) | | is_alive(self) | Return whether process is alive | | join(self, timeout=None) | Wait until child process terminates | | run(self) | Method to be run in sub-process; can be overridden in sub-class | | start(self) | Start child process | | terminate(self) | Terminate process; sends SIGTERM signal or uses TerminateProcess()
#1、设置daemon都为True import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("good",)) create_one_process.daemon = True create_one_process.start() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",)) create_two_process.daemon = True create_two_process.start() print("third") ''' output: first second third ''' #2、设置daemon都为False import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("good",)) create_one_process.daemon = False create_one_process.start() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",)) create_two_process.daemon = False create_two_process.start() print("third") ''' output: first second third good nice ''' #3、设置daemon一个True一个False import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("good",)) create_one_process.daemon = True create_one_process.start() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",)) create_two_process.daemon = False create_two_process.start() print("third") ''' output: first second third nice ''' #4、设置daemon一个False一个True import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("good",)) create_one_process.daemon = False create_one_process.start() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("nice",)) create_two_process.daemon = True create_two_process.start() print("third") ''' output: first second third good '''
import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("1",)) create_one_process.daemon = True create_one_process.start() create_one_process.join() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("2",)) create_two_process.daemon = True create_two_process.start() #create_two_process.join() print("third") '''output: first 1 second third ''' import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": print("first") create_one_process = multiprocessing.Process(target=create_test_function,args=("1",)) create_one_process.daemon = True create_one_process.start() create_one_process.join() print("second") create_two_process = multiprocessing.Process(target=create_test_function,args=("2",)) create_two_process.daemon = True create_two_process.start() create_two_process.join() print("third") '''output: first 1 second 2 third '''
import multiprocessing import time,datetime def create_test_function(statement): time.sleep(2) print(statement) if __name__ == "__main__": for i in xrange(4): create_one_process = multiprocessing.Process(target=create_test_function,args=(i,)) create_one_process.daemon = True create_one_process.start() create_one_process.join() print("cheers")
2、Queue
Queue的功能是将每个核或线程的运算结果放在队里中, 等到每个线程或核运行完毕后再从队列中取出结果, 继续加载运算。原因很简单, 多线程调用的函数不能有返回值, 所以使用Queue存储多个线程运算的结果。
import multiprocessing as mp def job(q): res=0 for i in range(1000): res+=i+i**2+i**3 q.put(res) #queue if __name__=='__main__': q = mp.Queue() p1 = mp.Process(target=job,args=(q,)) p2 = mp.Process(target=job,args=(q,)) p1.start() p2.start() p1.join() p2.join() res1 = q.get() res2 = q.get() print(res1+res2)
3、Pool
进程池就是我们将所要运行的东西,放到池子里,Python会自行解决多进程的问题。 Pool和之前的Process的不同点是丢向Pool的函数有返回值,而Process的没有返回值。
对于需要使用几个甚至十几个进程时,我们使用Process还是比较方便的,但是如果要成百上千个进程,用Process显然太笨了,multiprocessing提供了Pool类,即现在要讲的进程池,能够将众多进程放在一起,设置一个运行进程上限,每次只运行设置的进程数,等有进程结束,再添加新的进程。
Pool(processes =num):设置运行进程数,当一个进程运行完,会添加新的进程进去
apply_async(函数,(参数)):非阻塞,其中参数是tulpe类型,
apply(函数,(参数)):阻塞
close():关闭pool,不能再添加新的任务
terminate():结束运行的进程,不再处理未完成的任务
join():和Process介绍的作用一样, 但要在close或terminate之后使用。
import multiprocessing as mp def job(x): return x*x def multicore(): pool = mp.Pool() res = pool.map(job, range(10)) print(res) if __name__ == '__main__': multicore()
#coding=utf-8 #Pool默认大小是CPU的核数,我们也可以通过在Pool中传入processes参数即可自定义需要的核数量, import multiprocessing as mp def job(x): return x*x def multicore(): pool = mp.Pool(processes=3) # 定义CPU核数量为3 res = pool.map(job, range(10)) print(res) if __name__ == '__main__': multicore()
#coding=utf-8 #apply_async()中只能传递一个值,它只会放入一个核进行运算,但是传入值时要注意是可迭代的,所以在传入值后需要加逗号, 同时需要用get()方法获取返回值。 import multiprocessing as mp def job(x): return x*x def multicore(): pool = mp.Pool() res = pool.map(job, range(10)) print(res) res = pool.apply_async(job, (2,)) # 用get获得结果 print(res.get()) if __name__ == '__main__': multicore()
#coding=utf-8 #用 apply_async() 输出多个结果 。 import multiprocessing as mp def job(x): return x*x def multicore(): pool = mp.Pool() res = pool.map(job, range(10)) print(res) res = pool.apply_async(job, (2,)) # 用get获得结果 print(res.get()) # 迭代器,i=0时apply一次,i=1时apply一次等等 multi_res = [pool.apply_async(job, (i,)) for i in range(10)] # 从迭代器中取出 print([res.get() for res in multi_res]) if __name__ == '__main__': multicore()
1、Pool默认调用是CPU的核数,传入processes参数可自定义CPU核数
2、map() 放入迭代参数,返回多个结果
3、apply_async()只能放入一组参数,并返回一个结果,如果想得到map()的效果需要通过迭代
4、共享内存
#我们可以通过使用Value数据存储在一个共享的内存表中。 import multiprocessing as mp value1 = mp.Value('i', 0) value2 = mp.Value('d', 3.14) #其中d和i参数用来设置数据类型的,d表示一个双精浮点类型,i表示一个带符号的整型。
#在Python的mutiprocessing中,有还有一个Array类,可以和共享内存交互,来实现在进程之间共享数据。 array = mp.Array('i', [1, 2, 3, 4]) #这里的Array和numpy中的不同,它只能是一维的,不能是多维的。同样和Value 一样,需要定义数据形式,否则会报错。
各参数代表的数据类型 | Type code | C Type | Python Type | Minimum size in bytes | | --------- | ------------------ | ----------------- | --------------------- | | `'b'` | signed char | int | 1 | | `'B'` | unsigned char | int | 1 | | `'u'` | Py_UNICODE | Unicode character | 2 | | `'h'` | signed short | int | 2 | | `'H'` | unsigned short | int | 2 | | `'i'` | signed int | int | 2 | | `'I'` | unsigned int | int | 2 | | `'l'` | signed long | int | 4 | | `'L'` | unsigned long | int | 4 | | `'q'` | signed long long | int | 8 | | `'Q'` | unsigned long long | int | 8 | | `'f'` | float | float | 4 | | `'d'` | double | float | 8 |
5、进程锁
为了解决不同进程抢共享资源的问题,我们可以用加进程锁来解决。
#coding=utf-8 import multiprocessing as mp import time def job(v, num, l): l.acquire() # 锁住 for _ in range(5): time.sleep(0.1) v.value += num # 获取共享内存 print(v.value) l.release() # 释放 def multicore(): l = mp.Lock() # 定义一个进程锁 v = mp.Value('i', 0) # 定义共享内存 p1 = mp.Process(target=job, args=(v,1,l)) # 需要将lock传入 p2 = mp.Process(target=job, args=(v,3,l)) p1.start() p2.start() p1.join() p2.join() if __name__ == '__main__': multicore()
---------------------------------------------------------------------------------------------
并行、并发、同步、异步、阻塞、非阻塞
自己的不确定性理解:
(同步:某个线程调用一直等待系统调用结果返回,才会执行)
(异步:某个线程调用没有等待系统调用结果返回,就直接执行)
(阻塞:)
(非阻塞:)
并行:多个CPU核心,不同的程序就分配给不同的CPU来运行。可以让多个程序同时执行。
并发:单个CPU核心,在一个时间切片里一次只能运行一个程序,如果需要运行多个程序,则串行执行。
同步与阻塞,异步与非阻塞的区别:
同步与异步是对应的,它们是线程之间的关系,两个线程之间要么是同步的,要么是异步的。
阻塞与非阻塞是对同一个线程来说的,在某个时刻,线程要么处于阻塞,要么处于非阻塞。
阻塞是使用同步机制的结果,非阻塞则是使用异步机制的结果。
一、概念
1. 同步:调用时,在没有得到结果之前,该调用就不返回,按照这个定义,绝大多数函数都是同步调用。一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。
最常见的例子就是 SendMessage。
2. 异步:调用者不会立刻得到结果,调用发出后,通过状态(效率低)、通知,或回调函数来通知调用者。PostMessgae。
3. 同步异步的区别:如何通知调用者得到调用结果,同步等待调用完成,异步通过状态、通知,或回调函数。
4. 阻塞:调用结果返回之前,当前线程会被挂起。socket的read/write/recv
5. 同步与阻塞的区别:同步当前线程还是激活的,只是从逻辑上当前函数没有返回而已。
6. 非阻塞:不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
7. 异步与非阻塞的区别:非阻塞是立刻返回调用结果,异步不会立刻返回调用结果,而是通过状态,通知,回调。
8. 异步与阻塞的关系:异步也会调用阻塞的函数,比如用select 函数,当select 返回可读时再去read 一般都不会被阻塞,但是read是一个阻塞的函数。
9. 同步异步和阻塞非阻塞之间的区别:同步异步是如何通知的概念,阻塞和非阻塞是如何执行的概念。
二、 同步/异步与阻塞/非阻塞的组合分析
同步阻塞形式: 等待执行结果是一直等待,执行时线程挂起(未对fd 设置O_NONBLOCK 标志位的read/write 操作)
同步非阻塞形式:等待执行结果是一直等待,执行时函数立即返回(对fd 设置O_NONBLOCK 标志位的read/write 操作)
异步阻塞形式:不是在处理消息时一直等待(通过状态、通知,或回调函数通知主调函数select ),而是在等待消息被触发时被阻塞(线程挂起).如果select 函数,的最后一个timeout 参数为NULL,程序就会停止在select这里。
异步非阻塞形式:在处理消息是不等待,在执行消息是也不等待。
6、上下文和启动方法
根据不同的平台, multiprocessing 支持三种启动进程的方法。这些启动方法有:
spawn
父进程会启动一个全新的 python 解释器进程。 子进程将只继承那些运行进程对象的 run() 方法所必需的资源。 特别地,来自父进程的非必需文件描述符和句柄将不会被继承。 使用此方法启动进程相比使用 fork 或 forkserver 要慢上许多。
可在Unix和Windows上使用。 Windows上的默认设置。
fork
父进程使用 os.fork() 来产生 Python 解释器分叉。子进程在开始时实际上与父进程相同。父进程的所有资源都由子进程继承。请注意,安全分叉多线程进程是棘手的。
只存在于Unix。Unix中的默认值。
forkserver
程序启动并选择* forkserver * 启动方法时,将启动服务器进程。从那时起,每当需要一个新进程时,父进程就会连接到服务器并请求它分叉一个新进程。分叉服务器进程是单线程的,因此使用 os.fork() 是安全的。没有不必要的资源被继承。
可在Unix平台上使用,支持通过Unix管道传递文件描述符。