python中的多进程

只有一个子进程:

# 多线程的实现
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=('test1',))
    print('Child process will start')
    p.start()
    p.join()
    print('Child process end')

p就是创建的子进程,里面两个参数分别是子进程要实现的函数和args(参数)

通过p.start()来开始

打印:

Parent process 3116.
Child process will start
Run child process test1 (1580)..
Child process end

getpid()是获取进程的标号的,每个进程都会有一个标号

进程池:

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)
    end=time.time()
    print('Task %s runs %.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 7148.
Waiting for all subprocesses done...
Run task 0 (956)
Run task 1 (22768)
Run task 2 (5188)
Run task 3 (20580)
Task 2 runs 1.16 seconds.
Run task 4 (5188)
Task 0 runs 2.00 seconds.
Task 3 runs 2.51 seconds.
Task 1 runs 2.87 seconds.
Task 4 runs 1.79 seconds.
All subprocesses done

我们解读一下:先是主进程开始,然后进入子进程task0-4是立即执行的,然后因为task2执行的比较快,所以他就会在task4之前打印出来1.16s,如果我们不加上p.join():

Parent process 15156.
Waiting for all subprocesses done...
All subprocesses done

就没有子进程了,所以join就是会等待子线程全部执行完才会结束

 

p=Pool(4)表示开启4个进程

 

进程之间的通讯

#线程之间的通讯
from multiprocessing import Process,Queue
import os,time,random
def write(q):
    print('Process to write:%s'% os.getpid())
    for value in ['mason','mike','lucy']:
        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__':
    q=Queue()
    pw=Process(target=write,args=(q,))#写操作的子进程
    pr=Process(target=read,args=(q,))#读操作的子进程
    pw.start()
    pr.start()
    pw.join()
    pr.terminate()

这是设置了两个进程,一个用来写一个用来读,用一个multiprocessing里面的Queue来装数据。注意以下几点:

(1) 在实例化Queue类,可以传递最大消息数,如q = Queue(5),这段代码是指只允许消息队列中最大有5个消息数据。如果不加最大消息数或数量为负值,则表达不限制数量直到占满内存; 
(2) Queue.qsize():返回当前队列包含的消息数量; 
(3) Queue.empty():如果队列为空,返回True,反之False ; 
(4) Queue.full():如果队列满了,返回True,反之False; 
(5) Queue.get([block[, timeout]]):获取队列中的一条消息,然后将其从列队中移除,block默认值为True; 
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果为空,此时程序将被阻塞(停在读取状态),直到从消息列队读到消息为止,如果设置了timeout,则会等待timeout秒,若还没读取到任何消息,则抛出”Queue.Empty”异常; 
2)如果block值为False,消息列队如果为空,则会立刻抛出”Queue.Empty”异常; 

(6) Queue.get_nowait():相当Queue.get(False); 
(7) Queue.put(item,[block[, timeout]]):将item消息写入队列,block默认值为True; 
1)如果block使用默认值,且没有设置timeout(单位秒),消息列队如果已经没有空间可写入,此时程序将被阻塞(停在写入状态),直到从消息列队腾出空间为止,如果设置了timeout,则会等待timeout秒,若还没空间,则抛出”Queue.Full”异常; 
2)如果block值为False,消息列队如果没有空间可写入,则会立刻抛出”Queue.Full”异常; 
(8) Queue.put_nowait(item):相当Queue.put(item, False);

(9)pr.terminate()是关闭进程的意思,但是它又不会马上就关闭:

p.terminate() # 关闭进程,不会立即关闭,所以is_alive立刻查看的结果可能还是存活
    print(p.is_alive())  # True
    time.sleep(0.1)
    print(p.is_alive()) # False

 

 

还可以写成:

def write(q):
    print('Process to write:%s'% os.getpid())
    for value in ['mason','mike','lucy']:
        print('Put %s to queue'%value)
        q.put(value)
        time.sleep(1)
def read(q):
    print('Process to read:%s'%os.getpid())
    while not q.empty():
        value=q.get(True)
        print('Get %s from queue.'%value)
        time.sleep(1)

这样就需要两个进程sleep的时间相同,因为我们while的条件的是队列不空

 

如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息: 
RuntimeError: Queue objects should only be shared between processes through inheritance.

# pool进程通讯
from multiprocessing import Manager, Pool
import time
def write(q):
    for i in ["A", "B", "C", "D", "E"]:
        print("向队列中添加%s" % i)
        q.put(i)
        time.sleep(1)
def read(q):
    while not q.empty():
        print("从队列中取出的值是%s" % q.get())
        time.sleep(1)
if __name__ == '__main__':
    q = Manager().Queue()
    pool = Pool(2)
    pool.apply_async(write, args=(q,))
    pool.apply_async(read, args=(q,))
    pool.close()
    pool.join()
    print("数据通信完毕")

至于为什么使用pool线程通讯一定要multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),请参考:

https://www.cnblogs.com/zhiyong-ITNote/p/7204722.html?utm_source=itdadao&utm_medium=referral(这个文章里面还有线程跟进程的区别,请认真阅读)

多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。

其他参考文章:

https://blog.csdn.net/longdreams/article/details/78197153

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值