PythonThread_06_bj

复习
孤儿进程和僵尸进程?
如何避免僵尸进程产生?
multiprocessing 创建进程
Process start join


multiprocessing 模块创建进程

  1. 需要将要做的事件进行封装成函数
  2. 使用multiprocessing提供的类Process创建进程对象
  3. 通过对象和Process的初始化函数对进程进行设置以
    及绑定要执行的事件
  4. 启动进程,会自动的执行函数代表的事件
  5. 完成进程的回收

创建进程对象
Process()
功能:创建进程对象
参数:name : 给创建的进程对象起一个名字
默认为Process-1
target : 绑定的函数
args :元组 用来给 target函数传参按位置传参
kwargs : 字典 按照键值传参

p.start()
功能:启动进程 进程被创建,自动运行对应函数

p.join([timeout])
功能 : 阻塞等待对应子进程的退出,回收子进程
参数 : 超时时间

  • 如果不使用join 则子进程会成为僵尸进程
  • 在使用multiprocessing创建进程中,一般父进程功能
    就是创建子进程等待回收,不做过多其他事情
  • 使用multiprocessing创建子进程,同样子进程复制父
    进程空间,之后有自己独立的执行空间,互不干扰

import multiprocessing as mp
from time import sleep

a = 1

def fun():
global a
a = 1000
sleep(3)
print(“子进程事件”)

#创建进程对象
p = mp.Process(target = fun)

#启动进程
p.start()

sleep(2)

print(“这是父进程”)

#回收进程
p.join()
print("a = ",a)


from multiprocessing import Process
from time import sleep
import os

def th1():
sleep(3)
print(“吃饭”)
print(os.getppid(),"----",os.getpid())
def th2():
sleep(2)
print(“睡觉”)
print(os.getppid(),"----",os.getpid())
def th3():
sleep(4)
print(“打豆豆”)
print(os.getppid(),"----",os.getpid())

thing = [th1,th2,th3]
process = []

for th in thing:
p = Process(target = th)
process.append§ #将进程对象保存
p.start()

#回收进程
for i in process:
i.join()

#01_process3.py

from multiprocessing import Process
from time import sleep

#带参数的事件函数
def worker(sec,name):
for i in range(3):
sleep(sec)
print(“I’m %s”%name)
print(“I’m working…”)

#创建进程,通过args,kwargs进行参数传递
p = Process(name = “Worker”,target = worker,
args = (2,),kwargs = {‘name’:“Alex”})
p.start()

#进程状态
print(“is alive :”,p.is_alive())
#进程名称
print(“Process name:”,p.name)
#进程pid
print(“Process PID:”,p.pid)
#回收进程
p.join(4) #4表示超时时间
print("===============")

is alive : True

Process name: Worker

Process PID: 5162

I’m Alex

I’m working…

I’m Alex

I’m working…

===============

I’m Alex

I’m working…


进程对象属性
p.join() 回收进程
p.start() 启动进程
p.is_alive() 判断进程是否在生命周期状态,在生命周
期中返回True 否则返回False

p.name 进程名称 默认为Process-1 如果起名字则为自
己取的名称

p.pid 进程的PID号

p.daemon
默认为False 主进程退出不会影响子进程
如果设置为 True 则主进程退出时会让所有子进程都退出

  • 该属性的设置必须在start() 前
  • 该属性一般不用和join同时出现

02_process4.py

from multiprocessing import Process
from time import sleep,ctime

def tm1():
while True:
sleep(2)
print(ctime())

p = Process(target = tm1)

p.daemon = True
p.start()
sleep(5)
print(“main process over”)

Mon Aug 6 14:56:12 2018

Mon Aug 6 14:56:14 2018

main process over

创建自定义进程类

1.继承Process类
2.运行Process类的__init__ 以获取父类属性
3.重写run方法,在通过自定类生成对象后,调用
start()会自动执行这个方法

03_clock.py

from multiprocessing import Process
import time

class ClockProcess(Process):
def init(self, value):
#使用父类的init保证同时拥有父类的属性
super(ClockProcess, self).init()
# Process.init(self)
self.value = value

#自定义的类中,重写run方法
def run(self):
    for i in range(5):
        print("The time is {}".\
            format(time.ctime()))
        time.sleep(self.value)

#用自己的类创建进程对象
p = ClockProcess(2)

会自动执行run方法

p.start()
p.join()

The time is Mon Aug 6 15:14:43 2018

The time is Mon Aug 6 15:14:45 2018

The time is Mon Aug 6 15:14:47 2018

The time is Mon Aug 6 15:14:49 2018

The time is Mon Aug 6 15:14:51 2018

多进程
优点 : 并行执行多个任务,提高效率
创建方便
运行独立,不受其他进程影响
数据安全
缺点 :在进程的创建和删除过程中消耗计算机资源较多

进程池技术

产生原因 :如果有大量的任务需要多进程完成,则可能
需要频繁的创建和删除进程,给计算机带来
较多的消耗。

使用 :大量可以短时间完成的任务需要多进程操作的时
候比较适用于进程池

使用方法:

  1. 创建进程池,在池内放入适当的进程
  2. 将事件加入进程池队列
  3. 事件不断运行,所有事件运行完成
  4. 关闭进程池,回收进程

from multiprocessing import Pool

Pool(processes)
功能 : 创建进程池对象
参数 : processes 表示进程池中有多少进程
对象 : 进程池对象

pool.apply_async(func,args,kwds)
功能 : 将事件放入进程池等待执行
参数 : func 要放入进程池的事件函数
args 给func函数以元组传参
kwds 给func函数以字典传参
返回值 : 返回一个事件对象
通过get()方法可以获取事件函数的返回值

pool.apply(func,args,kwds)
功能 : 将事件放入进程池等待执行
参数 : func 要放入进程池的事件函数
args 给func函数以元组传参
kwds 给func函数以字典传参

pool.close()
功能 : 关闭进程池 不能再添加新的事件

pool.join()
功能 : 回收进程池

04_pool.py

from multiprocessing import Pool
from time import sleep,ctime

def worker(msg):
sleep(2)
print(msg)
return ctime()

#创建进程池对象
pool = Pool(processes = 4)

result = []
for i in range(10):
msg = “hello %d”%i
#将事件加入到进程池
pool.apply(func = worker,args = (msg,))
# r = pool.apply_async(func = worker,args = (msg,))
# result.append®

#关闭进程池
pool.close()
#回收进程
pool.join()

#打印各个事件函数返回值

for i in result:

print(i.get())

# hello 0

# hello 2

# hello 3

# hello 1

# hello 5

# hello 6

# hello 4

# hello 7

# hello 9

# hello 8

# Mon Aug 6 16:00:22 2018

# Mon Aug 6 16:00:22 2018

# Mon Aug 6 16:00:22 2018

# Mon Aug 6 16:00:22 2018

# Mon Aug 6 16:00:24 2018

# Mon Aug 6 16:00:24 2018

# Mon Aug 6 16:00:24 2018

# Mon Aug 6 16:00:24 2018

# Mon Aug 6 16:00:26 2018

# Mon Aug 6 16:00:26 2018

hello 0

hello 1

hello 2

hello 3

hello 4

hello 5

hello 6

hello 7

hello 8

hello 9

pool.map(func,iter)
功能 : 将要完成的事件放入到进程池
参数 : func 要完成的事件函数
iter 要给func传递的参数的迭代器
返回值 : 返回事件函数的返回值列表

05_pool_map.py

from multiprocessing import Pool
import time

def fun(n):
time.sleep(1)
print(“执行 pool map 事件”,n)
return n * n

pool = Pool(4)
#map放入6个事件到进程池
r = pool.map(fun,range(6))
print(“返回值列表:”,r)
pool.close()
pool.join()

执行 pool map 事件 3

执行 pool map 事件 1

执行 pool map 事件 2

执行 pool map 事件 0

执行 pool map 事件 4

执行 pool map 事件 5

返回值列表: [0, 1, 4, 9, 16, 25]

练习 : 使用multiprocessing 创建两个进程,分别复制
一个文件的上半部分和下半部分到另外一个新的
文件中
cookie : os.path.getsize(path) 获取文件大小

#06_copy_file.py

import os
from multiprocessing import Process

#获取文件大小
size = os.path.getsize("./file.jpg")
#两个子进程操作同一个文件流会产生错乱

f = open(‘file.jpg’,‘rb’)

#复制前半部分
def copy1(filename):
f = open(filename,‘rb’)
n = size // 2
fw = open(‘copy1.jpg’,‘wb’)

while True:
    if n < 128:
        data = f.read(n)
        fw.write(data)
        break
    data = f.read(128)
    fw.write(data)
    n -= 128
f.close()
fw.close() 

#复制下半部分
def copy2(filename):
f = open(filename,‘rb’)
fw = open(‘copy2.jpg’,‘wb’)
f.seek(size // 2,0)
while True:
data = f.read(128)
if not data:
break
fw.write(data)
fw.close()
f.close()

p1 = Process(target = copy1,args = (“file.jpg”,))
p2 = Process(target = copy2,args = (“file.jpg”,))

p1.start()
p2.start()

p1.join()
p2.join()

进程间通信

进程间由于空间独立,资源互相无法直接获取,此时在不同
的进程间传递数据就需要专门的进程间通信方法。

和磁盘交互 : 使用中间文件 但是不安全,速度慢

进程间通信方法 (IPC)
管道 消息队列 共享内存 信号 信号量 套接字

管道通信 Pipe

在内存中开辟一块空间,形成管道结构,管道对多个进程可见,
进程可以通过对管道的读写操作进行通信

multiprocessing —》 Pipe

fd1,fd2 = Pipe(duplex = True)
功能 : 创建一个管道
参数 : 默认表示管道为双向管道
如果设置为False 则表示单向管道
返回值 : 返回两个管道流对象,表示管道两端
如果是双向管道,则都可以读写
如果是单向管道,则fd1只读 fd2只写

fd1.recv()
功能 : 从管道内读信息
返回值:读到的内容

  • 当管道内无内容时会阻塞

fd2.send(data)
功能 : 向管道写入内容
参数 : 要写的内容

  • 可以发送几乎Python的任意数据类型

#07_pipe.py

from multiprocessing import Process,Pipe
import os,time

#创建管道
fd1,fd2 = Pipe()

def fun(name):
time.sleep(3)
#向管道内写入内容
fd1.send(“hello” + str(name))

jobs = []
for i in range(5):
p = Process(target = fun,args = (i,))
jobs.append§
p.start()

for i in range(5):
#读取管道内消息
data = fd2.recv()
print(data)

for i in jobs:
i.join()

hello0

hello1

hello2

hello4

hello3

消息队列

队列 : 先进先出
在内存中开辟队列结构空间,对多个进程可见。多个进程向队列中存入消息,
取出消息,完成进程间通信。

创建队列
q = Queue(maxsize = 0)
功能 : 创建队列
参数 : maxsize 默认表示根据系统分配空间存储消息
如果传入一个正整数则表示最多存入消息数量
返回值 : 队列对象

q.put(data,[block,timeout])
功能 : 向队列中存入消息
参数 : data 存入的数据 (支持Python数据类型)
block 默认为True表示 当队列满时阻塞
设置为False 表示非阻塞
timeout 当block为Ture时表示超时时间

data = q.get([block,timeout])
功能 : 从队列获取消息
参数 : block 默认为True表示 当队列空时阻塞
设置为False 表示非阻塞
timeout 当block为Ture时表示超时时间
返回值:返回获取到的消息

q.full() 判断队列是否为满
q.empty() 判断队列是否为空
q.qsize() 获取队列中消息数量
q.close() 关闭队列

08_queue1.py

from multiprocessing import Queue
from time import sleep

#创建队列
q = Queue(3)

q.put(1)
sleep(1)
print(q.empty())

print(q.full())

q.put(2)

q.put(3)

print(q.full())

# q.put(4,True,3)

print(q.get())

print(q.qsize()) #查看消息数量

print(q.empty())

q.close()


08_queue2.py

from multiprocessing import Process,Queue
import time

#创建消息队列
q = Queue()

def fun1():
time.sleep(1)
q.put({‘a’:1,‘b’:2})

def fun2():
time.sleep(2)
print(“收到消息:”,q.get())

p1 = Process(target = fun1)
p2 = Process(target = fun2)
p1.start()
p2.start()
p1.join()
p2.join()

收到消息: {‘b’: 2, ‘a’: 1}

共享内存

在内存中开辟一段空间,存储数据,对多个进程可见。
每次写入共享内存的数据会覆盖之前的内容

from multiprocessing import Value,Array

obj = Value(ctype,obj)
功能 : 开辟共享内存空间
参数 : ctype 字符串 要转变的c的类型code(对照 ctype表)
obj 共享内存初始值
返回共享内存对象

obj.value 表示共享内存中的值。对其修改或者使用即
为使用共享内存中的值

obj = Array(ctype,obj)
功能 : 开辟共享内存空间
参数 : ctype 要转换的类型
obj 要存入共享内存的数据
列表 将列表存入共享内存 要求类型一致
整数 在共享内存中开辟几个单元的空间
返回共享内存对象

        管道        消息队列       共享内存

开辟空间 内存 内存 内存

读写方式 两端读写 先进先出 操作覆盖内存
双向/单向

效率 一般 一般 较快

应用 多用于父子 广泛灵活 复杂,需要
进程 互斥机制

10_value.py

from multiprocessing import Process,Value
import time
import random

#共享内存对象初始存放2000
money = Value(‘i’,2000)

#存钱进程
def deposite():
for i in range(100):
time.sleep(0.05)
#对value属性操作实际就是在操作共享内存
money.value += random.randint(1,200)
#取钱
def withdraw():
for i in range(100):
time.sleep(0.04)
#对value属性操作实际就是在操作共享内存
money.value -= random.randint(1,200)

d = Process(target = deposite)
w = Process(target = withdraw)

d.start()
w.start()

d.join()
w.join()
print(money.value)

11_array.py

from multiprocessing import Process,Array
import time

#创建共享内存 列表是共享内存初始值

shm = Array(‘i’,[1,2,3,4,5])

#表示共享内存中开辟5个整形空间
shm = Array(‘i’,5)

def fun():
for i in shm:
print(i)
#修改共享内存内容
shm[3] = 1000

p = Process(target = fun)
p.start()
p.join()
for i in shm:
print(i)

作业 : 熟练掌握进程间通信方法
自己实现进程池的使用,知道进程池特性

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值