多进程的使用(详解)---multiprocessing

前言:计算机时代发展迅速,从单核cpu发展为多核的cpu,从原始的单进程转变成现在的多进程执行任务,那么什么是多进程呢?要怎样使用呢,那么我来介绍一下吧!!!

进程:

1.进程的概念:

进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。 

进程是系统进行资源分配的基本单位,一台机器上可以有多个进程,每个进程执行不同的程序,每个进程相对独立,拥有自己的内存空间,隔离性和稳定性比较高,进程之间互不影响,但是资源共享相对麻烦,系统资源占用相对高,同时进程可以利用cpu多核资源,适合cpu密集型任务!

2.进程的分类

进程又分为单进程和多进程两种形式:

(1).单进程:

单进程:默认程序开启时创建一个进程,咱们所写的一个py文件就是一个进程,系统会分配资源开启一个进程去处理这个py文件,主线程去执行这个文件

(2).多进程

完成多任务,每一个进程各自执行各自的任务,各自互不干扰各干各的事儿,本文章主要讲多进程

3.进程的使用

进程使用需要multiprocessing库,往往是先声明进程实例,里面可以传入消费方法名称和不定长参数args,然后将实例放入指定进程数的容器中(list),通过循环或者列表推导式,使用start方法开启进程,join方法阻塞主进程。

(1).Process参数解析:

  • group:指定进程组,一般目前初学者也没有进程组就默认为None;
  • target:执行目标任务名;
  • name:进程名字;
  • args:以元组形式向执行任务传参;
  • kwargs:以字典形式向执行任务传参.

(2).Process创建实例对象:

  • start():启动子进程实例,也就是创建一个子进程;
  • join():等待主进程执行结束,监测主进程完成后,从而再去执行子进程;
  • terminate():不管任务是否完成,立即终止子进程.

(3).举例:

from multiprocessing import Process
import time

def job(num):

    time.sleep(1)

    print("子进程启动{}".format(num))

if __name__ == '__main__':


   [Process(target=job,args=(x,)).start() for x in range(100)]

    pool.close()
    pool.join()  #等待主进程执行结束,监测主进程完成后,从而再去执行子进程;

    pool.terminate() #不管任务是否完成,立即终止子进程.

4.进程的应用场景

进程可以利用cpu多核资源,适合cpu密集型任务,比如一些统计计算任务,比如计算广告转化率,uv、pv等等,或者一些视频的压缩解码任务,进程还有一个使用场景,就是后期部署项目的时候,nginx反向代理后端服务,往往需要开启多个tornado服务来支持后台的并发,就是利用了多进程的互不干扰,就算某个进程僵死,也不会影响其他进程。

5.进程间的通信

进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的。

队列queue:

不同于线程queue,进程queue的生成是用multiprocessing模块生成的。

在生成子进程的时候,会将代码拷贝到子进程中执行一遍,及子进程拥有和主进程内容一样的不同的名称空间。

multiprocess.Queue 是跨进程通信队列

常用方法

q.put方法用以插入数据到队列中,put方法还有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,该方法会阻塞timeout指定的时间,直到该队列有剩余的空间。如果超时,会抛出Queue.Full异常。如果blocked为False,但该Queue已满,会立即抛出Queue.Full异常。
q.get方法可以从队列读取并且删除一个元素。同样,get方法有两个可选参数:blocked和timeout。如果blocked为True(默认值),并且timeout为正值,那么在等待时间内没有取到任何元素,会抛出Queue.Empty异常。如果blocked为False,有两种情况存在,如果Queue有一个值可用,则立即返回该值,否则,如果队列为空,则立即抛出Queue.Empty异常.
q.get_nowait():同q.get(False)
q.put_nowait():同q.put(False)
q.empty():调用此方法时q为空则返回True,该结果不可靠,比如在返回True的过程中,如果队列中又加入了项目。
q.full():调用此方法时q已满则返回True,该结果不可靠,比如在返回True的过程中,如果队列中的项目被取走。
q.qsize():返回队列中目前项目的正确数量,结果也不可靠,理由同q.empty()和q.full()一样

管道queue:

管道就是管道,就像生活中的管道,两头都能进能出

默认管道是全双工的,如果创建管道的时候映射成False,左边只能用于接收,右边只能用于发送,类似于单行道

import multiprocessing

def foo(sk):
    sk.send('hello world')
    print(sk.recv())

if __name__ == '__main__':
    conn1,conn2=multiprocessing.Pipe()    #开辟两个口,都是能进能出,括号中如果False即单向通信
    p=multiprocessing.Process(target=foo,args=(conn1,))  #子进程使用sock口,调用foo函数
    p.start()
    print(conn2.recv())  #主进程使用conn口接收
    conn2.send('hi son') #主进程使用conn口发送

常用方法

conn1.recv():接收conn2.send(obj)发送的对象。如果没有消息可接收,recv方法会一直阻塞。如果连接的另外一端已经关闭,那么recv方法会抛出EOFError。
conn1.send(obj):通过连接发送对象。obj是与序列化兼容的任意对象
注意:send()和recv()方法使用pickle模块对对象进行序列化

6.进程池

开多进程是为了并发,通常有几个cpu核心就开几个进程,但是进程开多了会影响效率,主要体现在切换的开销,所以引入进程池限制进程的数量。进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

from multiprocessing import Process,Pool
import time

def job(num):

    time.sleep(1)

    print("子进程启动{}".format(num))

if __name__ == '__main__':

    pool = Pool(4)


   # [Process(target=job,args=(x,)).start() for x in range(100)]

    [pool.apply_async(func=job,args=(x,)) for x in range(100)]

    pool.close()
    pool.join()
    pool.terminate()

结果:

 7.进程的状态

1)就绪状态(Ready):

进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。

2)运行状态(Running):

进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。

3)阻塞状态(Blocked):

由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法运行

8.线程在进程中

通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在引入线程操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
multiprocessingPython 自带的一个多进程模块,可以方便地启动进程并进行进程间通信。multiprocessing 启动进程的三种方法如下: 1. 使用 Process 类启动进程 Process 类是 multiprocessing 模块中启动进程的核心类,通过创建 Process 类的实例对象并调用 start() 方法,即可启动一个新的进程。例如: ```python from multiprocessing import Process def func(): print('Hello, world!') if __name__ == '__main__': p = Process(target=func) p.start() ``` 2. 使用 Pool 类启动进程池 Pool 类可以帮助我们创建进程池,将多个进程任务分配给进程池中的进程处理。例如: ```python from multiprocessing import Pool def func(x): return x * x if __name__ == '__main__': p = Pool(4) result = p.map(func, [1, 2, 3, 4]) print(result) ``` 以上代码中,创建了一个进程池,最大进程数为 4。将任务列表 [1, 2, 3, 4] 分配给进程池中的进程处理,并通过 map() 方法返回处理结果。 3. 使用 Manager 类启动进程间通信 Manager 类可以帮助我们创建进程间共享的数据结构,例如列表、字典、队列等。例如: ```python from multiprocessing import Manager, Process def func(l): l.append('Hello, world!') if __name__ == '__main__': manager = Manager() l = manager.list() p = Process(target=func, args=(l,)) p.start() p.join() print(l) ``` 以上代码中,使用 Manager 类创建了一个共享列表 l,将其作为参数传递给子进程。子进程向列表中添加了一条记录后,主进程通过 join() 方法等待子进程执行完毕,然后打印出列表 l 的内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值