多进程 multiprocessing模块 学习笔记

多进程的定义

提高效率(增加并发数)

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

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

多进程的特性

并发性:任何进程在操作系统中可以同时运行
独立性:资源不共享
异步性:进程和进程之间相互制约,进程运行有间断性

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:子进程函数需要携带的参数,需元组类型传入

扫描二维码关注公众号,回复: 1930508 查看本文章

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

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

运行结果为:

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

进程间的资源共享

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

我们以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( )等来实现




猜你喜欢

转载自blog.csdn.net/qq_37275405/article/details/80791038