Process属于multiprocess中的一个类
- 例1:
import os
from multiprocessing import Process # 因为在内部做了一些操作所以可以直接拿到Process类,可以通过这个类启动进程
def func():
print('子进程',os.getpid(), os.getppid())
if __name__ == '__main__': # 只在windouws操作系统要写这句话,再linux和mac系统上不用写。
print('主进程', os.getpid(), os.getppid())
p = Process(target = func) # 实例化Process类。创建进程对象。此时没有开启此进程,func函数再子进程中执行,而不是在主进程中执行。
p.start() # 开启进程
运行结果
主进程 14668 11392 # 主进程的id成了子进程的父进程
子进程 7616 14668 # 子进程和主进程同时运行。
为什么要写if __name__ == '__main__':
各个进程之间有什么特点
- 异步
- 数据隔离
数据隔离问题:进程直接的数据是不同的数据隔离问题:进程直接的数据是不同的
import os
import time
from multiprocessing import Process
count = 100
def func():
global count
count -= 1
print('子进程:', count)
if __name__ == '__main__':
print('主进程', os.getpid(), os.getppid())
p = Process(target=func)
p.start()
time.sleep(2)
print('主进程:', count)
运行结果
主进程 14708 11392
子进程: 99
主进程: 100
import os
import time
from multiprocessing import Process
count = 100
def func():
global count
count -= 1
print('子进程__name__:', __name__)
print('>>>',__name__)
if __name__ == '__main__':
print('主进程', os.getpid(), os.getppid())
p = Process(target=func)
print('启动子进程')
p.start()
print('结束子进程')
运行结果
>>> __main__
主进程 7148 11392
启动子进程
结束子进程
>>> __mp_main__ # 由于windows执行子进程时执行了主进程中程序,所以打印了子进程的__name__,也就是子进程的空间名
子进程__name__: __mp_main__
父进程和子进程的关系
父进程只负责通知操作系统启动子进程
接下来的工作由操作系统接手,父进程继续执行
父进程执行完毕后并不会直接结束程序,
而是会等待所有的子进程都执行完毕之后才结束
父进程要负责回收子进程的资源。也就是告诉操作系统,子进程全部执行完毕,通知操作系统子进程全部执行完毕,叫操作系统释放命名空间或把变量清空等。只有主进程有权限通知操作系统的级别。
- 例2:
from multiprocessing import Process
import time
def f(name):
time.sleep(1)
print('hello', name, time.ctime())
if __name__ == '__main__':
p_list = []
for i in range(3):
p = Process(target=f, args=('laura',))
p_list.append(p)
p.start()
for i in p_list:
i.join()
print('end')
运行结果:
hello laura Sat Sep 22 11:21:47 2018
hello laura Sat Sep 22 11:21:47 2018
hello laura Sat Sep 22 11:21:47 2018
end
实例:
原生socket写并发程序
server端
import socket
sk = socket.socket() # sk对象
sk.bind(('127.0.0.1', 9000))
sk.listen()
while True: # 循环接收连接
conn, addr = sk.accept() # 此时conn可以通信了。
while True: # 一直和别人send,recv,别人一直想和我连,我一直和另外一个人说话,这样就不能收到连接了。因为在里面的while True 不出来,外面的while True就执行不了了。
conn.send(b'hello')
print(conn.recv(1024))
# 解决方法:把跟别人聊天这件事情交给一个子进程做,这样第一个循环就可以实现了。
from multiprocessing import Process
def communicate(conn):
while True:
conn.send(b'hello')
print(conn.recv(1024))
if __name__ == '__main__':
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
while True:
conn, addr = sk.accept()
Process(target=communicate, args=(conn,)).start() # 由于这句是在主进程写的,并且不希望在子进程中循环下去。所以要加一个if __name__ == '__main__'
client端
import socket
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
while True:
print(sk.recv(1024)) # 那边先send,所以先recieve
sk.send(b'bye')
join同步控制
join属于Process类中的一个方法
模拟十个进程分别发送十封邮件
import time
import random
from multiprocessing import Process
def func(index):
time.sleep(random.random()) # 0到1秒直接随机睡一会儿
print('第%s个邮件已经发送完毕' % index)
if __name__ == '__main__':
for i in range(10):
Process(target=func, args=(i, )).start() # 十个子进程异步执行,让十个进程分别发十个邮件。
print('10个邮件已经发送完毕') # 最为主进程我想知道我的十个进程已经执行完了
运行结果
10个邮件已经发送完毕
第4个邮件已经发送完毕
第0个邮件已经发送完毕
第8个邮件已经发送完毕
第2个邮件已经发送完毕
第7个邮件已经发送完毕
第9个邮件已经发送完毕
第5个邮件已经发送完毕
第1个邮件已经发送完毕
第3个邮件已经发送完毕
第6个邮件已经发送完毕
由于主进程和子进程完全异步,所以同时打印出来了,如图
可我要的结果是子进程全部执行完了再打印这句话。
Procee类中的join方法能够帮助我们知道子进程是什么时候结束的。作用:阻塞直到p进程执行完毕就结束阻塞。
用join方法实现同步控制
import time
import random
from multiprocessing import Process
def func(index):
time.sleep(random.randint(1, 3))
print('第%s个邮件已经发送完毕' % index)
if __name__ == '__main__':
p = Process(target=func, args=(1, ))
p.start()
p.join()
print('1个邮件已经发送完毕')
运行结果
第1个邮件已经发送完毕
1个邮件已经发送完毕
现在让十个进程异步发邮件,所有进程发完邮件后,才打印所有邮件发送完毕。相当于主进程和n个子进程同步了。
join在哪个进程下面就会在等待哪个进程。
import time
import random
from multiprocessing import Process
def func(index):
time.sleep(random.random())
print('第%s个邮件已经发送完毕' % index)
if __name__ == '__main__':
p_list = []
for i in range(10):
p = Process(target=func, args=(i, ))
p.start()
p_list.append(p)
for p in p_list:
p.join() # 十个进程都开启了之后,这十个进程都要执行完才执行以下代码。
print('10个邮件已经发送完毕') # 一定是在最后才打印这句话
运行结果
第2个邮件已经发送完毕
第4个邮件已经发送完毕
第1个邮件已经发送完毕
第9个邮件已经发送完毕
第3个邮件已经发送完毕
第6个邮件已经发送完毕
第7个邮件已经发送完毕
第5个邮件已经发送完毕
第8个邮件已经发送完毕
第0个邮件已经发送完毕
10个邮件已经发送完毕
例:输出资源,屏幕为进程间共享资源时。
from multiprocessing import Process, Lock
import time
def f(l, i):
# with l: # 加把锁把屏幕控制了,谁先拿到锁谁先在屏幕输出。相当于串行 # 加了with就不用l.acquire()和l.realease()了
l.acquire()
time.sleep(1) # 运行了10秒,如果没有锁,运行时间不用1秒
print('hello world %s' % i)
l.release()
if __name__ == '__main__':
print(time.time())
lock = Lock()
list1 = []
for num in range(10):
p = Process(target=f, args=(lock, num))
p.start()
list1.append(p)
for i in list1:
i.join()
print(time.time())
运行结果
1537682507.537764
hello world 0
hello world 1
hello world 2
hello world 3
hello world 4
hello world 5
hello world 6
hello world 8
hello world 7
hello world 9
1537682517.8930845