12、多进程

一、多进程

Python中的多线程无法利用多核优势,如果想要充分地使用多核CPU的资源(os.cpu_count()查看),在python中大部分情况需要使用多进程。Python提供了multiprocessing

multiprocessing模块用来开启子进程,并在子进程中执行我们定制的任务(比如函数),该模块与多线程模块threading的编程接口类似。

multiprocessing模块的功能众多:支持子进程通信和共享数据执行不同形式的同步,提供了ProcessQueuePipeLock等组件。

1、Process类

构造方法:

Process([group [, target [, name [, args [, kwargs]]]]])
  group: 线程组,目前还没有实现,库引用中提示必须是None; 
  target: 要执行的方法; 
  name: 进程名; 
  args/kwargs: 要传入方法的参数。

一般情况下:只需要传入target和args参数即可。

常用实例方法**:

  • is_alive():返回进程是否在运行。
  • join([timeout]):阻塞当前上下文环境的进程程,直到调用此方法的进程终止或到达指定的timeout(可选参数)。
  • start():进程准备就绪,等待CPU调度
  • run()strat()调用run方法,如果实例进程时未制定传入target,这star执行默认run()方法。
  • terminate():不管任务是否完成,立即停止工作进程

主要属性
name:进程名字。
pid:进程号。

使用Process类创建多进程的两种方法,方法一:

import os
from multiprocessing

#子进程要执行的代码
def run_proc():
    print ('子进程本身的id, os.getpid())     # os.getpid() 用于获取子进程的id
    print('父进程的id, os.getppid())            # os.getppid() 用于获取父进程的id

If __name__ == '__main__’:
    print ('父进程id% os.getpid()) # 在父进程中获取父进程的id
    for i in range(10):
    	p = multiprocessing.Process(target = run_proc, args=())
    	p.start()
    p.join()

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

方法二:

import time
from multiprocessing import Process

class MyProcess(Process):
    
    def __init__(self, arg):
        super(MyProcess, self).__init__()
        self.arg = arg

    def run(self):
        print('say hi', self.arg)
        time.sleep(1)

if __name__ == '__main__':
    for i in range(10):
        p = MyProcess(1)
        p.start()

进程之间默认是不能共用内存的:

li = []
 
def f1(i):
    li.append(i)
    print('你好',li)
 
if __name__ =='__main__':#进程不能共用内存
    for i in range(10):
        p = Process(target=f1,args=(i,))
        p.start()

'''每个进程都创建一个列表,然后添加一个因素进去,
   每个进程之间的数据是不能共享的'''
2、Pool

如果要启动大量的子进程,可以用进程池的方式批量创建子进程。
(1)apply模块的使用,每个任务是排队执行的

from multiprocessing import Process,Pool
from multiprocessing import Manager
import time
 
 
def f1(a):
    time.sleep(2)
    print(a)
 
if __name__ =='__main__':
    pool =Pool(5)
    for i in range(5):  # 每次使用的时候会去进程池里面申请一个进程
        pool.apply(func=f1,args=(i,))
        print('你好')  # apply里面是每个进程执行完毕了才执行下一个进程
    
    pool.close()  # 执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束
    pool.join()  # 等待进程运行完毕,先调用close函数,否则会出错

(2)apply_async模块,会比apply模块多个回调函数,同时是异步的

from multiprocessing import Process,Pool
from multiprocessing import Manager
import time
 
 
 
def Foo(i):
    time.sleep(1)
    return i+50
 
def Bar(arg):
    print(arg)
 
if __name__ =='__main__':
    pool = Pool(5)
    for i in range(10):
 
        '''apply是去简单的去执行,而apply_async是执行完毕之后可以执行一
        个回调函数,起提示作用'''
        pool.apply_async(func=Foo,args=(i,),callback=Bar)#是异步的
        print('你好')
    pool.close()	# 不执行close会报错,因为join的源码里面有个断言会检验是否执行了该方法
    pool.join()		# 等待所有子进程运行完毕,否则的话由于apply_async里面daemon是设置为True的,
    
    # 主进程不会等子进程,所欲函数可能会来不及执行完毕就结束了
'''apply_async里面,等函数Foo执行完毕,它的返回结果会被当做参数传给Bar'''

applyapply_async方法的主要区别

#进程池
p = pool(5)

p.apply                   # 每个任务是排队执行的,进程.join()
p.apply_async       	  # 每一个任务都是并发的,可以设置回调函数,进程.join(),
                    	  # 若无jion(),则进程daemon=True,不等待子进程,主进程结束则全部结束。
3、进程数据共享

方法一:使用Array

Array('i’, range(10))中的'i'参数C语言中的类型:

'c’: ctypes.c_char     
'u’: ctypes.c_wchar    
'b’: ctypes.c_byte     
'B’: ctypes.c_ubyte
'h’: ctypes.c_short     
'H’: ctypes.c_ushort    
'i’: ctypes.c_int      
'I’: ctypes.c_uint
'l’: ctypes.c_long,    
'L’: ctypes.c_ulong    
'f’: ctypes.c_float    
'd’: ctypes.c_double

示例:

from multiprocessing import Process, Array

def f(a):
    for i in range(len(a)):
        a[i] = -a[i]

if __name__ == '__main__':
    arr = Array('i', range(10))
    p = Process(target=f, args=(arr,))
    p.start()
    p.join()

    print(arr[:])

运行结果:

[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]

方法二:使用manager
Manager()返回的manager提供list, dict, Namespace, Lock, RLock, Semaphore, BoundedSemaphore, Condition, Event, Barrier, Queue, Value and Array类型的支持。

from multiprocessing import Process
from multiprocessing import Manager
 

def f1(i,dic):
    dic[i] = 200+i
    print(dic.values())
 
if __name__ =='__main__':	# 进程间默认不能共用内存
    manager = Manager()
    dic = manager.dict()	# 这是一个特殊的字典
 
 
    for i in range(10):
        p = Process(target=f1,args=(i,dic))
        p.start()
        p.join()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值