Python_multiprocessing

一、基本概念

        fork()调用一次,返回两次,因为操作系统自动把当前进程复制了一份,然后分别在父子进程内返回。子进程永远返回0,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用getpid()就可以拿到父进程的ID。

二、multiprocessing

       multiprocessing模块提供了一个Process类来代表一个进程对象,进程创建:Process(target=主要运行的函数,name=自定义进程名称可不写,args=(参数))。下面的例子演示了启动一个子进程并等待其结束:

from multiprocessing import Process
import os

# 子进程要执行的代码
def run_proc(name):
    print('Run child process %s (%s)...' % (name, os.getpid()))

if __name__=='__main__':
    print('Parent process %s.' % os.getpid())
    p = Process(target=run_proc, args=('test',))
    print('Child process will start.')
    p.start()
    p.join()
    print('Child process end.')

执行结果:
Parent process 51832.
Child process will start.
Run child process test (51972)...
Child process end.

        其中:创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

is_alive()判断进程是否存活
join([timeout])子进程结束再执行下一步,timeout为超时时间,有时进程遇到阻塞,为了程序能够运行下去而设置超时时间
run()如果在创建Process对象的时候不指定target,那么就会默认执行Process的run方法
start()启动进程,区分run()
terminate()终止进程,关于终止进程没有这么简单,貌似用psutil包会更好,有机会以后了解更多再写下。

三、Pool

        如果要启动大量的子进程,可以用进程池的方式批量创建子进程:

Pool(processes =num)设置运行进程数,当一个进程运行完,会添加新的进程进去
apply_async(函数,(参数))非阻塞,其中参数是tulpe类型
apply(函数,(参数))阻塞
close()关闭pool,不能再添加新的任务
terminate()结束运行的进程,不再处理未完成的任务
join()和Process介绍的作用一样, 但要在close或terminate之后使用
from multiprocessing import Pool
import os,time,random

def long_time_task(name):
    print('Run task %s (%s)...'%(name,os.getpid()))
    start = time.time()                #返回当前时间的时间戳
    time.sleep(random.random()*3)      #返回随机生成的一个实数,它在[0,1)范围内。
    end = time.time()
    print('Task %s runs %0.2f seconds.'%(name,(end - start)))

if __name__ =='__main__':
    print('Parent process %s.'%os.getpid())
    p = Pool(4)
    for i in range(5):
        p.apply_async(long_time_task, args=(i,))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')

执行结果:
Parent process 39360.
Waiting for all subprocesses done...
Run task 0 (9312)...
Run task 1 (5680)...
Run task 2 (37780)...
Run task 3 (34748)...
Task 2 runs 0.57 seconds.
Run task 4 (37780)...
Task 3 runs 1.05 seconds.
Task 0 runs 1.10 seconds.
Task 1 runs 2.14 seconds.
Task 4 runs 2.06 seconds.
All subprocesses done.

        其中需要特别注意的是:对Pool对象调用join()方法会等待所有子进程执行完毕调用join()之前必须先调用close(),调用close()之后就不能继续添加新的Process了。请注意输出的结果,task 0,1,2,3是立刻执行的,而task 4要等待前面某个task完成后才执行,这是因为Pool的默认大小在我的电脑上是4,因此,最多同时执行4个进程。这是Pool有意设计的限制,并不是操作系统的限制。

三、进程间通信

        Process之间肯定是需要进行通信的,操作系统提供了很多机制来实现进程间的通信。Python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据。

        1、Queue

from multiprocessing import Process,Queue
import os,time,random

#写数据进程执行的代码:
def write(q):
    print('Process to write: %s'%(os.getpid()))
    for value in ['A','B','C']:
        print('Put %s to queue...'%(value))
        q.put(value)
        time.sleep(random.random())
#读数据进程执行的代码:
def read(q):
    print('Process to read:%s'%(os.getpid()))
    while True:
        value = q.get(True)
        print('Get %s from queue.'%(value))

if __name__ == '__main__':
    # 父进程创建queue,并传给子进程:
    q = Queue()
    pw = Process(target = write ,args= (q,))
    pr = Process(target = read, args= (q,))
    #启动子进程pw,写入:
    pw.start()
    #启动子进程pr,读取:
    pr.start()
    #等待pw结束:
    pw.join()
    #pr进程里是死循环。无法等待其结束,只能强行终止:
    pr.terminate()

显示结果:
Process to write: 51344
Put A to queue...
Process to read:52252
Get A from queue.
Put B to queue...
Get B from queue.
Put C to queue...
Get C from queue.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值