python基础____学习笔记9 ( 多进程创建 、进程间通信)

一、多进程

1.1 创建多进程
    需要引入包:

import multiprocessing

  函数原型:

Process([group [, target [, name [, args [, kwargs]]]]])
  • group:指定进程组,目前只能使用None
  • target:执行的目标任务名
  • name:进程名字
  • args:以元组方式给执行任务传参
  • kwargs:以字典方式给执行任务传参

Process创建的实例对象的常用方法:

  • start():启动子进程实例(创建子进程)
  • join():等待子进程执行结束
  • terminate():不管任务是否完成,立即终止子进程

实例1:
 

import multiprocessing
import time
import os

# 带有参数的任务
def task(name,count):
    print("%s process pid %d ppid: %d"  % (name,os.getpid(),os.getppid()))
    for i in range(count):
        print(f"{name}任务执行中..")
        time.sleep(0.2)
    else:
        print(f"{name}任务执行完成")

if __name__ == '__main__':
    # 创建子进程
    # args: 以元组的方式给任务传入参数
    sub_process1 = multiprocessing.Process(target=task, args=('xiaoming',5))
    sub_process2 = multiprocessing.Process(target=task, kwargs={'name' : 'xiaozhang', 'count': 5})
    sub_process1.start()
    sub_process2.start()

    sub_process1.join()
    sub_process2.join()
    print('主进程结束')

输出:

xiaoming process pid 7948 ppid: 10628
xiaoming任务执行中..
xiaozhang process pid 4280 ppid: 10628
xiaozhang任务执行中..
xiaoming任务执行中..
xiaozhang任务执行中..
xiaoming任务执行中..
xiaozhang任务执行中..
xiaoming任务执行中..
xiaozhang任务执行中..
xiaoming任务执行中..
xiaozhang任务执行中..
xiaoming任务执行完成
xiaozhang任务执行完成
主进程结束

注意:   进程之间不共享全局变量

1.2 继承方式创建多进程
自定义进程类,继承至processs ,并实现run方法

from multiprocessing import Process
import time
import os


class MyProcess(Process):

    def __init__(self, name, count):
        Process.__init__(self)
        self.name = name
        self.count = count
    def run(self):
        print("%s process pid %d ppid: %d" % (self.name, os.getpid(), os.getppid()))
        for i in range(self.count):
            print(f"{self.name}任务执行中..")
            time.sleep(0.2)
        else:
            print(f"{self.name}任务执行完成")

if __name__ == '__main__':
    # 创建子进程
    # args: 以元组的方式给任务传入参数
    sub_process1 = MyProcess('xiaoming', 5)
    sub_process2 = MyProcess('xiaozhang', 5)
    sub_process1.start()
    sub_process2.start()

    sub_process1.join()
    sub_process2.join()
    print('主进程结束')

注意: 子类中的__init__() 函数中一定要调用  Process.__init__(self)  

1.3 守护进程

主进程创建守护进程

       守护进程会在主进程代码执行结束后就终止

      守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes are not allowed to have children

      进程之间是互相独立的,主进程结束,非守护进程仍然在运行

from multiprocessing import Process
import time
import os


class MyProcess(Process):

    def __init__(self, name, count):
        Process.__init__(self)
        self.name = name
        self.count = count
    def run(self):
        print("%s process pid %d ppid: %d" % (self.name, os.getpid(), os.getppid()))
        for i in range(self.count):
            print(f"{self.name}任务执行中..")
            time.sleep(0.2)
        else:
            print(f"{self.name}任务执行完成")

if __name__ == '__main__':
    # 创建子进程
    # args: 以元组的方式给任务传入参数
    sub_process1 = MyProcess('xiaoming', 5)
    sub_process2 = MyProcess('xiaozhang', 5)
    sub_process2.daemon=True
    sub_process1.start()
    sub_process2.start()

    #sub_process1.join()
    #sub_process2.join()
    print('主进程结束')

这里将sub_process2.daemon=true 设置为守护进程,所以当主进程结束,守护进程sub_process2 马上就结束了,不再打印

xiaoming process pid 7744 ppid: 10636
xiaoming任务执行中..
xiaoming任务执行中..
xiaoming任务执行中..
xiaoming任务执行中..
xiaoming任务执行中..
xiaoming任务执行完成

1.4    进程同步

与Linux 进程类似,父进程创建子进程,子进程从父进程将申请的资源拷贝,子进程更改这些资源 并不影响父进程,但是操作文件时这些物理上只有 一个的时候,就需要加锁 互斥访问,避免访问资源冲突。
       使用互斥锁 需要导入 Lock,

from multiprocessing import Lock

lock.acquire()
#共
#享
#资
#源
lock.release()  


1.5 使用os.fork创建子进程
熟悉Linux的都知道,Linux 使用fork来创建子进程

import os
import time

print('Process (%d) start...' % os.getpid())
count = 10
pid = os.fork()
if pid < 0:
    print('Created a child process failed ')
elif pid == 0:
    count += 5
    print('In child process %d and my parent is %d.' % (os.getpid(), os.getppid()))
    print(f'Chiled count={count}')
else:
    count += 3
    print('In Parent process %d .' % (os.getpid()))
    print(f'Parent count={count}')
    time.sleep(1)
print(f'end count={count}')

输出:

Process (12273) start...
In Parent process 12273 .
Parent count=13
In child process 12274 and my parent is 12273.
Chiled count=15
end count=15
end count=13

父进程创建子进程,子进程拷贝父进程的变量count,父子进程改变count 都相互独立,互补影响.
注意: os.fork 只支持Linux ,windows不支持
 

1.6 进程池
当需要创建大量的进程时候,可以考虑使用进程池Pool

import multiprocessing
from multiprocessing import Pool
import time
import os

# 带有参数的任务
def task(name,count):
    print("%s process pid %d ppid: %d"  % (name,os.getpid(),os.getppid()))
    for i in range(count):
        print(f"{name}任务执行中..")
        time.sleep(0.2)
    else:
        print(f"{name}任务执行完成")

if __name__ == '__main__':
    p = Pool(6)
    for i in range(6):
        name = 'kaikai-'+str(i)
        count = 4
        p.apply_async(task, args=(name,count))
    print('Waiting for all subprocesses done...')
    p.close()
    p.join()
    print('All subprocesses done.')
    print('主进程结束')
  • apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的,非阻塞意思是创建几个进程 并行执行互补影响,阻塞意思是创建的第一个进程执行完成后,才创建第二个进程
  • close()          关闭pool,使其不在接受新的任务。
  • terminate()    结束工作进程,不在处理未完成的任务。
  • join()          主进程阻塞,等待子进程的退出, join方法要在close或terminate之后使用。

二、 进程间通信

进程间通信方式有7种与Linux进程间通信是一样的,如下
msg_queue (消息队列)
pipeline for single duplex (单工管道)
pipeline for half duplex (半双工管道)
name pipeline (命名管道)
share memory (共享内存)
semaphore (信号量)
socket (套接字)

2.1 消息队列
消息队列使用 Queue模块

from multiprocessing import Process
from multiprocessing import Queue
from time import sleep

def produce(q):
    for i in range(3):
        print('put %d to queue..' % i)
        q.put(i)
        sleep(0.5)
def comsumer(q):
    while 1:
        if q.empty():
            continue
        v = q.get(True)
        print('get %d from queue..' % v)

if __name__ == '__main__':
    q = Queue()
    p1 = Process(target=produce, args=(q,))
    p2 = Process(target=comsumer, args=(q,))
    p1.start()
    p2.start()
    p1.join()
    while not q.empty():
        sleep(0.5)
    p2.terminate()  # 结束p2进程

输出:

put 0 to queue..
get 0 from queue..
put 1 to queue..
get 1 from queue..
put 2 to queue..
get 2 from queue..

2.1 单工管道:

管道使用Pipe()创建管道,返回来个connection ,一个写 一个读

from multiprocessing import Process, Pipe
import time

def f1(conn):
    count  = 0
    while count <=100 :
        conn.send('hello word-{}'.format(count))
        count +=1
        time.sleep(0.2)
def f2(conn):
    while True:
        recvstr=conn.recv()
        print(recvstr)
        if recvstr == 'hello word-100':
            break
if __name__ == '__main__':
    parent_conn, child_conn = Pipe()
    parentP = Process(target=f1, args=(parent_conn,))
    childP = Process(target=f2, args=(child_conn,))
    parentP.start()
    childP.start()
    childP.join()
    parentP.join()
    print('parent Process exit')

输出:
 

hello word-0
hello word-1
hello word-2
hello word-3
hello word-4

.
.
.

hello word-99
hello word-100
parent Process exit

管道只允许有亲缘关系的进程间通信
Pipe()有个参数 duplex
如果duplex为True(默认),则管道是双向的。
如果duplex是False,那么管道是单向的:conn1只能用于接收消息,conn2只能用于发送消息。

2.2  命名管道
命名管道可以用于两个没有血缘关系的进程间通信
     每个FIFO管道都与一个路径名相关联,类似一个文件.  不建议使用
2.3 信号量
s = multiprocessing.Semaphore(2)  #把信号量值设置为2,一次提供给两个消费者服务
不传输数据,用于多进程的同步
s.acquire()      #信号量的使用与互斥量类似
s.release()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值