当前位置 : 主页 > 编程语言 > python >

多进程 multiprocessing模块 学习笔记

来源:互联网 收集:自由互联 发布时间:2022-06-18
多进程的定义 提高效率(增加并发数) 进程是程序一次动态的执行过程,包括代码加载,执行,执行完毕退出阶段 进程是系统资源分配的独立单位(最小单位) 进程拥有自己独立的堆


多进程的定义

提高效率(增加并发数)

进程是程序一次动态的执行过程,包括代码加载,执行,执行完毕退出阶段

进程是系统资源分配的独立单位(最小单位)


进程拥有自己独立的堆和栈,既不共享堆,亦不共享栈,进程由操作系统调度。

多进程的特性

并发性:任何进程在操作系统中可以同时运行

独立性:资源不共享

异步性:进程和进程之间相互制约,进程运行有间断性

os.fork()

Unix/Linux操作系统提供了一个os.fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

子进程永远返回​​0​​,而父进程返回子进程的ID。这样做的理由是,一个父进程可以fork出很多子进程,所以,父进程要记下每个子进程的ID,而子进程只需要调用os.getppid()就可以拿到父进程的ID。

实例:

import os
import time

def child():
print('我是子进程,id是:%d,父进程id是:%d' % (os.getpid(),os.getppid()))
time.sleep(30) #当主进程结束 子进程还在运行时 子进程的ppid为 0
os._exit(0) #结束子进程
def parent():
while True:
newpid = os.fork() #Unix/Linux操作系统才有的方法
if newpid == 0: # 子进程
child()
else:
print('我的父进程id是:%d ------ 子进程id是:%d' % (os.getpid(),newpid))
if input() == 'q':
break
parent()

运行结果为:

我是子进程,id是:10026,父进程id是:10025
我的父进程id是:10025 ------ 子进程id是:10026


multiprocessing

由于python是跨平台的语言,但是windows上又没有os.fork()方法,所以multiprocessing模块就是跨平台版本的多进程模块

multiprocessing提供了一个类Process来创建子进程对象,(帽提剖赛应)

from multiprocessing import Process
import os

def chilid(name):
print('我是子进程%s我的进程id是%d'%(name,os.getpid()))
print('我的父级进程是%s'%os.getppid())
if __name__ == '__main__': #必须加if判断
print('我是父级进程%s'%os.getpid())
p = Process(target=chilid,args=("test",)) #创建子进程
p.start()#开启子进程
p.join() #等待所有进程运行完毕

target : 子进程运行的函数

args:子进程函数需要携带的参数,需元组类型传入

start( ):让子进程开启运行

join( ):方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步。

运行结果为:

我是父级进程14556
我是子进程test我的进程id是15744
我的父级进程是14556

进程间的资源共享

因为进程与进程之间资源不共享,但我们process之间又要通信,所以Python包装了底层的机制,提供了​​Queue​​、​​manage​​等多种方式来交换数据。

我们以multiprocessing中的manage方法为例,来实现多个进程向一个资源里添加数据

import multiprocessing
from multiprocessing import Manager
#子进程执行函数
def foo(a,i):
a.append(i)

if __name__ == '__main__':
#实例化资源共享对象
m = Manager()
a = m.list() #使用共享对象创建列表list 也可以创建共享Queue,dict等

p_list = []#进程列表
for i in range(10):
#创建一个子进程对象
p = multiprocessing.Process(target=foo,args=(a,i))
#开始执行子进程
p.start()
p_list.append(p)#把所有进程加入进程列表

for p in p_list:
p.join() #等待所有进程执行完毕再继续往下执行

print(a)
print("执行完毕")

执行结果为:

[2, 1, 3, 0, 4, 6, 7, 5, 8, 9]
执行完毕

常用函数:

q.qsize( )返回当前队列包含的消息数量

q.full( )表示当前队列是否已经满了 True--满了 False--未满

q.empty( )表示当前队列是否为空 True--空 False--不为空

q.put( )(消息,block=True,timeout=None) 

q.get(block=True,timeout=None)

    block(默认True) -- 阻塞(停在put状态)直到put进去为止

    timeout(默认None) --一直等 如果设置timeout则会等待N秒 然后强制put

q.put_nowait( ) --相当于q.put(消息,False)

q.get_nowait( ) --相当于q.get(False)

pool

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

Pool 可以提供指定数量的进程供用户使用,默认是 CPU 核数。当有新的请求提交到 Poll 的时候,如果池子没有满,会创建一个进程来执行,否则就会让该请求等待。 

- Pool 对象调用 join 方法会等待所有的子进程执行完毕 

- 调用 join ( )方法之前,必须调用 close( ) 

- 调用 close 之后就不能继续添加新的 Process 了

实例

from multiprocessing import Pool
import requests

def tasl(url):
response = requests.get(url)
print(response)

if __name__ == '__main__':
#使用Pool创建12个进程
pool = Pool(12)
base_url = 'https://hr.tencent.com/position.php?start=%d'
for i in range(0,3760+1,10):
fullurl=base_url % i
#使用apply_async 方法用来异步执行进程,允许多个进程同时进入池子。
pool.apply_async(func=tasl,args=(fullurl,))

#关闭进程池 进程池中不能再创造新的进程
pool.close()
#等待进程池中所有进程运行完毕
pool.join()


总结:

在Unix/Linux下,可以使用os.fork( )电调用实现多进程。

想实现跨平台需使用multiprocessing模块

想多进程间通信可以使用multiprocessin.Manage或queue.Queue( )等来实现




上一篇:python协程之gevent模块
下一篇:没有了
网友评论