【Python】多线程 & 多进程(2)

多进程

Python 多进程和多线程的使用方式非常类似,同样也支持 Lock、RLock、Condition、Semaphore、Event这几种同步方式

但每个进程享有独立的内存数据,因此需要用到 Manage、Queue、Pipe、Value 和 Array 实现数据共享

# 摘自: http://www.cnblogs.com/kaituorensheng/p/4445418.html

# 函数作为进程
import multiprocessing
import time

def worker(interval):
    n = 5
    while n > 0:
        print("The time is {0}".format(time.ctime()))
        time.sleep(interval)
        n -= 1

if __name__ == "__main__":
    p = multiprocessing.Process(target = worker, args = (3,))
    p.start()
    print "p.pid:", p.pid
    print "p.name:", p.name
    print "p.is_alive:", p.is_alive()

# 类作为进程
import multiprocessing
import time

class ClockProcess(multiprocessing.Process):
    def __init__(self, interval):
        multiprocessing.Process.__init__(self)
        self.interval = interval

    def run(self):
        n = 5
        while n > 0:
            print("the time is {0}".format(time.ctime()))
            time.sleep(self.interval)
            n -= 1

if __name__ == '__main__':
    p = ClockProcess(3)
    p.start() 

进程池 Pool

  • 对于大数量的进程,可以用 Pool 自动管理
  • 向 Pool 指定进程数量,当有新进程请求时,如果Pool还没满则创建,否则等待直到有进程结束
  • 有阻塞型和非阻塞型两种,前者等当前进程结束后才开启下一个进程(顺序执行了),后者一次塞满(如果有)Pool
#coding: utf-8
import multiprocessing
import time

def func(msg):
    print "msg:", msg
    time.sleep(3)
    print "end"

if __name__ == "__main__":
    pool = multiprocessing.Pool(processes = 3)
    for i in xrange(4):
        msg = "hello %d" %(i)
        # 非阻塞
        pool.apply_async(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        # 阻塞
        # pool.apply(func, (msg, ))

    print "Mark~ Mark~ Mark~~~~~~~~~~~~~~~~~~~~~~"
    pool.close()
    pool.join()   #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
    print "Sub-process(es) done."

进程间数据共享

1)队列 Queue

  • 需要注意的是,这里的队列是 multiprocessing.Queu
    多线程里的队列是 Queue
  • Pool里不支持使用Queue
from multiprocessing import Process, Queue  
def test(queue):  
    queue.put("Hello World")  
if __name__ == '__main__':
    q = Queue(5)  
    p = Process(target=test, args=(q,))  #需要将q对象传递给子进程
    p.start()
    print q.get()

2)Array 和 Value

  • Value 用于共享单个值,Array用于共享一个数组
  • 两个都需要指定值类型
  • Pool里不支持使用
import multiprocessing as mp
import time


def job(val, arr, p):
    for _ in range(len(arr)):
        val.value += p
        arr[i] += p
        print('proces %s, val=%s, arr=%s' % (p, val.value, arr[:]))
        time.sleep(0.5)  # 暂停0.5秒,让输出效果更明显


if __name__ == '__main__':
    val = mp.Value('d', 3.14)  # Value
    arr = mp.Array('i', range(3))  # Array

    print('val=%s, arr=%s' % (val.value, arr[:]))
    print("start...")

    p1 = mp.Process(target=job, args=(val, arr, 1))
    p2 = mp.Process(target=job, args=(val, arr, 2))
    p1.start()
    p2.start()
    p1.join()
    p2.join()

    print('val=%s, arr=%s' % (val.value, arr[:]))
    print("done...")
Type codeC TypePython Type
‘b’signed charint
‘B’unsigned charint
‘i’signed intint
‘I’unsigned intint
‘f’floatfloat
‘d’doublefloat

3)Manager 类

  • 类似于服务器与客户之间的通信,主进程作为服务器,存放共享资源,其他进程作为客户端访问
  • 提供 list、dict()等(multiprocessing.Manager.list()、multiprocessing.Manager.dict())
  • Linux 和 Windows 有差异:Windows下 Manager 的声明只能在 main 下,并通过参数传给子进程(会消耗大量资源,速度很慢),Linux没这个问题
# 摘自:https://thief.one/2016/11/24/Multiprocessing%E5%85%B1%E4%BA%AB%E8%B5%84%E6%BA%90/

# Linux 下

from multiprocessing import Manager,Pool
lists=Manager().list()    ##定义可被子进程共享的全局变量lists
def test(i):
     print i
     lists.append(i)
if __name__=="__main__":
    pool=Pool()
    for i in xrange(10000000):
        '''
        判断如果lists长度大于0,则不再往进程池中添加进程。
        '''
        if len(lists)<=0:
            pool.apply_async(test,args=(i,))
        else:
            break
     pool.close()
     pool.join()
# Windows 下

from multiprocessing import Manager
def test(i,lists):
     print i
     lists.append(i)
if __name__=="__main__":
    pool=Pool()
    lists=Manager().list() #Manager类实例化代码只能写在main()函数里面
    for i in xrange(10000000):
        if len(lists)<=0:
            '''
            在创建子进程时,需要将lists对象传入,不然无法共享。
            '''
            pool.apply_async(test,args=(i,lists))##需要将lists对象传递给子进程,这里比较耗资源,原因可能是因为Manager类是基于通信的。
        else:
            break

4)管道 Pipe

  • Pipe仅适用于两个进程通信,有单向和双向模式:
    multiprocessing.Pipe(True) # 双向
    multiprocessing.Pipe(False) #单向
  • Pipe**效率远高于Queue**
  • Pipe方法返回(conn1, conn2),代表管道的两个端,单向模式时,conn1用来接收,conn2用来发送
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import multiprocessing
import time

m = 5


def proc1(pipe):
    for i in range(m):
        print("proc1 send %s" % (i))
        pipe.send(i)
        time.sleep(1)


def proc2(pipe):
    flag = 0
    while True:
        if flag >= m - 3:
            pipe.close()  # 关闭
        flag += 1
        print("proc2 rev %s" % (pipe.recv()))
        time.sleep(1)


if __name__ == "__main__":
    pipe = multiprocessing.Pipe()
    p1 = multiprocessing.Process(target=proc1, args=(pipe[0],))
    p2 = multiprocessing.Process(target=proc2, args=(pipe[1],))
    print("start")
    p1.start()
    p2.start()
    p1.join()
    p2.join()
    print("end")
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值