0510进程 multiprocess模块

process模块是一个创建进程的模块,借助这个模块,就可以完成进程的创建。

创建模块
import os
import time
from multiprocessing import Process

def func(n,name,num = 20):
    print(os.getpid(),os.getppid())
    time.sleep(1)

if __name__ == '__main__':
    print(os.getpid(),os.getppid())  # process id,parent process id
    Process(target=func,args=[1,'alex',30]).start()    # func
    print('*'*20)
    time.sleep(0.5)
    print('*'*40)
    # p = Process(target=func)
    # p.start()

# 主进程默认会等待子进程执行完毕之后才结束
# 主进程和子进程之间的代码是异步的
# 为什么主进程要等待子进程结束 回收一些子进程的资源
# 开启一个进程是有时间开销的 :操作系统响应开启进程指令,给这个进程分配必要的资源
强调: 1. 需要使用关键字的方式来指定参数 2. args指定的为传给target函数的位置参数,是一个元组形式,必须有逗号 参数介绍: 1 group参数未使用,值始终为None 2 target表示调用对象,即子进程要执行的任务 3 args表示调用对象的位置参数元组,args=(1,2,'egon',) 4 kwargs表示调用对象的字典,kwargs={'name':'egon','age':18} 5 name为子进程的名称

方法介绍:
1 p.start():启动进程,并调用该子进程中的p.run() 
2 p.run():进程启动时运行的方法,正是它去调用target指定的函数,我们自定义类的类中一定要实现该方法  
3 p.terminate():强制终止进程p,不会进行任何清理操作,如果p创建了子进程,该子进程就成了僵尸进程,使用该方法需要特别
         小心这种情况。如果p还保存了一个锁那么也将不会被释放,进而导致死锁 4 p.is_alive():如果p仍然运行,返回True 5 p.join([timeout]):主线程等待p终止(强调:是主线程处于等的状态,而p是处于运行的状态)。timeout是可选的超时时
            间,需要强调的是,p.join只能join住start开启的进程,而不能join住run开启的进程。


属性介绍:
1 p.daemon:默认值为False,如果设为True,代表p为后台运行的守护进程,当p的父进程终止时,p也随之终止,并且设定
      为True后,p不能创建自己的新进程,必须在p.start()之前设置
2 p.name:进程的名称
3 p.pid:进程的pid
4 p.exitcode:进程在运行时为None、如果为–N,表示被信号N结束(了解即可)
5 p.authkey:进程的身份验证键,默认是由os.urandom()随机生成的32字符的字符串。这个键的用途是为涉及网络连接的底层
       进程间通信提供安全性,这类连接只有在具有相同的身份验证键时才能成功(了解即可)

在Windows操作系统中由于没有fork(linux操作系统中创建进程的机制),在创建子进程的时候会自动 import 启动它的这个文件,
而在 import 的时候又执行了整个文件。因此如果将process()直接写在文件中就会无限递归创建子进程报错。所以必须把创建子
进程的部分使用if __name__ ==‘__main__’ 判断保护起来,import 的时候 ,就不会递归运行了。

同步控制
import os
from multiprocessing import Process
def func(exp):
print(os.getpid(),os.getppid())
result = eval(exp)
with open('file','w') as f:
f.write(str(result))

if __name__ == '__main__':
print(os.getpid(),os.getppid()) # process id,parent process id
# 3*5+5/6
p = Process(target=func,args=['3*5']) # func
p.start()
ret = 5/6
p.join() # join方法能够检测到p进程是否已经执行完了,阻塞直到p执行结束
with open('file') as f:
result = f.read()
ret = ret + int(result)
print(ret
)
join :阻塞 直到 子进程结

开启多个进程
import os
import time
from multiprocessing import Process

def process(n):
print(os.getpid(),os.getppid())
time.sleep(1)
print(n)
if __name__ == '__main__':
p_lst = []
for i in range(10):
p = Process(target=process,args=[i,])
p.start()
p_lst.append(p)
for p in p_lst:p.join() # 检测p是否结束 如果没有结束就阻塞直到结束 如果已经结束了就不阻塞
print('求和')
还有一种以继承Process类的形式开启进程的方式
import os
from multiprocessing import Process
class Myprocess(Process):
def __init__(self,*args):
super().__init__()
self.args = args
def run(self):
print(os.getpid(),self.name,self.pid)
for name in self.args:
print('%s和女主播聊天'%name)

if __name__ == '__main__':
print(os.getpid())
p = Myprocess('yuan','wusir')
p.start() # 在执行start的时候,会帮我们主动执行run方法中的内容
进程中的数据隔离
from multiprocessing import Process
n = 100
def func():
global n
n += 1
print('son : ',n) #son : 101

if __name__ == '__main__':
p = Process(target=func)
p.start()
p.join()
print(n) #100
守护进程
import time
from multiprocessing import Process

def func():
print('son start')
while True:
time.sleep(1)
print('son')

def func2():
print('start :in func2')
time.sleep(5)
print('end : in func2')
if __name__ == '__main__':
p = Process(target=func)
# 在一个进程开启之前可以设置它为一个守护进程
p.daemon = True
p.start()
Process(target=func2).start()
time.sleep(2)
print('在主进程中')
分析:
主进程的代码 大概在2s多的时候就结束了
p2子进程实在5s多的时候结束
主进程结束
p是在什么时候结束的?
p是在主进程的代码执行完毕之后就结束了

主进程会等待子进程的结束而结束
守护进程的意义:
子进程会随着主进程代码的执行结束而结束
注意:守护进程不会关心主进程什么时候结束,我只关心主进程中的代码什么时候结束
守护进程的作用:
守护主进程,程序报活
主进程开启的时候 建立一个守护进程
守护进程只负责每隔1分钟 就给检测程序发一条消息
进程中的其他属性和方法
import time
from multiprocessing import Process

def func():
print('wahaha')
time.sleep(20)
print('wahaha end')
if __name__ == '__main__':
p = Process(target=func)
p.start()
print(p.is_alive())
time.sleep(1)
p.terminate() # 在主进程中结束一个子进程
print(p.is_alive())
time.sleep(0.5)
print(p.is_alive())
print(p.pid) #相当于self.pid 查看进程ID
print(p.name) #相当于self.name 查看进程名

使用多进程实现socket聊天并发-server

server端
import socket
from multiprocessing import Process
def func(conn):
    while True:
        msg = conn.recv(1024).decode('utf-8')
        print(msg)
        conn.send('sb'.encode('utf-8'))
    conn.close()

if __name__ == "__main__":
    sk = socket.socket()
    sk.bind(('127.0.0.1', 9000))
    sk.listen()
    while True:
        conn, addr = sk.accept()
        Process(target=func,args=[conn,]).start()
    sk.close()

client端
import socket

sk = socket.socket()
sk.connect(('127.0.0.1',9000))
while True:
    inp = input('>>>').encode('utf-8')
    sk.send(inp)
    msg = sk.recv(1024).decode('utf-8')
    print(msg)
sk.close()

import os
import time
import random
from multiprocessing import Process
from multiprocessing import Lock
def work(n,lock):
    lock.acquire()
    print('%s: %s in running'%(n,os.getpid()))
    time.sleep(random.random())
    print('%s:%s in done'%(n,os.getpid()))
    lock.release()

if __name__ =='__main__':

    lock = Lock()
    for i in range(10):
        p = Process(target=work, args=(i,lock))
        p.start()

抢票系统
import json
import time
import random
from multiprocessing import Process,Lock
def chenck(i):
with open('file')as f:
count = json.load(f)
print('percon%s,剩余%s张票'%(i,count['count']))
time.sleep(random.random())

def buy(i,lock):
chenck(i)
lock.acquire()
with open('file')as f:
count = json.load(f)
time.sleep(random.random())#模拟读数据的网络延迟
if count['count'] > 0:
print('%s抢票成功'%i)
else:
print('%s抢票失败'%i)
time.sleep(random.random())#模拟读数据的网络延迟

with open('file','w')as f:
count['count'] -= 1
json.dump(count,f)
lock.release()

if __name__ == '__main__':
lock = Lock()
for i in range(10): #模拟并发10个客户端抢票
Process(target=buy, args=[i, lock]).start()
上面这种情况虽然使用加锁的形式实现了顺序的执行,但是程序又重新变成串行了,这样确实会浪费了时间,却保证了数据的安全。
加锁可以保证多个进程修改同一块数据时,同一时间只能有一个任务可以进行修改,即串行的修改,没错,速度是慢了,但牺牲了速
度却保证了数据安全。 虽然可以用文件共享数据实现进程间通信,但问题是: 1.效率低(共享数据基于文件,而文件是硬盘上的数据) 2.需要自己加锁处理

信号量

KTV 4个房子
import time
import random
from multiprocessing import Process,Semaphore
def ktv(i,sem):
    sem.acquire()
    print('person %s 进来唱歌了'%i)
    time.sleep(random.randint(1,5))
    print('person %s 从ktv出去了'%i)
    sem.release()

if __name__ == '__main__':
    sem = Semaphore(4)
    for i in range(10):
        Process(target=ktv,args=(i,sem)).start()

锁+计数器
.acquire() 计数器-1
计数器减为0 = 阻塞
.release() 计数器+1

事件--------------红绿灯

multiprocess.Event(了解)

状态 # 子进程 如何 受到状态的影响? # wait() 的方法 等待 ---> 信号 # 发送信号:通过事件来发送信号 # True set 把信号设置为True # False clear 把信号设置位False # 红绿灯 : # 车 进程 wait() 等红灯 # 根据状态变化 wait遇到True信号,就非阻塞 # 遇到False信号,就阻塞 # 交通灯 进程 红灯 --> False # 绿灯 --> True # 事件 # wait的方法 根据一个状态来决定自己是否要阻塞 # 状态相关的方法 # set 将状态改为T # clear 将状态改为F # is_set 判断当前的状态是否为T # from multiprocessing import Event # # 创建一个事件的对象 # e = Event() # print(e.is_set()) # 在事件的创世之初,状态为False # e.set() # e.wait() # print(e.is_set()) # e.clear() # print(e.is_set()) # e.wait() import time import random from multiprocessing import Process,Event def car(i,e): # 感知状态的变化 if not e.is_set(): # 当前这个事件的状态如果是False print('car%s正在等待'%i) # 这辆车正在等待通过路口 e.wait() # 阻塞 直到有一个e.set行为 # 等红灯 print('car%s通过路口'%i) def traffic_light(e): # 修改事件的状态 print('\033[1;31m红灯亮\033[0m') # 事件在创立之初的状态是False,相当于我程序中的红灯 time.sleep(2) # 红灯亮2s while True: if not e.is_set(): # False print('\033[1;32m绿灯亮\033[0m') e.set() elif e.is_set(): print('\033[1;31m红灯亮\033[0m') e.clear() time.sleep(2) if __name__ == '__main__': e = Event() Process(target=traffic_light,args=[e,]).start() for i in range(50): time.sleep(random.randrange(0,5,2)) Process(target=car,args=[i,e]).start()

进程间通信——队列和管道(multiprocess.Queue、multiprocess.Pipe)

 

posted @ 2018-05-11 23:01  Murray穆  阅读(364)  评论(0编辑  收藏  举报