python中启动子进程
并发编程
并发 :多段程序看起来是同时运行的
ftp 网盘
不支持并发
socketserver 多进程 并发
异步
两个进程 分别做不同的事情
创建新进程
join :阻塞 直到 子进程结束
守护进程 daemon :子(守护)进程随着主进程代码的结束而结束
进程之间数据隔离
使用类来开启一个进程 :自定义类 继承Process 重写run方法 传参数需要重写init
属性 pid name
方法 terminate is_alive
作业讲解:
socket聊天并发实例,使用原生socket的TCP协议,实现一个聊天的并发实例
先来一个简单的,单线程
server.py
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
msg = conn.recv(1024).decode('utf-8')
conn.send((msg+'sb').encode('utf-8'))
print(msg)
conn.close()
client.py
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
inp = input('>>>').encode('utf-8')
sk.send(inp)
msg = sk.recv(1024).decode('utf-8')
print(msg)
sk.close()
先执行server.py,再执行client.py
输出:
>>>111
111sb
如果要多次会话呢?加一个while循环
server.py
import socket
sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
conn,addr = sk.accept()
while True:
msg = conn.recv(1024).decode('utf-8')
conn.send((msg+'sb').encode('utf-8'))
print(msg)
conn.close()
sk.close()
client.py
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()
但是这样,只能一个客户端和服务器连接,再来一个客户端,就卡住了。
sk.accept()是阻塞的,那么,如何改成异步呢?
将server里面的recv和send放到一个函数里面,使用多线程调用
server.py
import socket
from multiprocessing import Process
def chat(conn): # 聊天
while True:
msg = conn.recv(1024).decode('utf-8')
print(msg)
conn.send((msg + '_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=chat,args=[conn,]).start() # 异步
sk.close()
先执行server.py,再执行client.py
多开几个客户端,也没问题
这就有点像接线员一样,接到客户打的电话,转给相应的人处理
这样,就有多个子进程,同时执行,实现多个客户端同时连接
进程同步(multiprocess.Lock、Semaphore、Event)
锁 —— multiprocess.Lock
通过刚刚的学习,我们千方百计实现了程序的异步,让多个任务可以同时在几个进程中并发处理,他们之间的运行没有顺序,一旦开启也不受我们控制。尽管并发编程让我们能更加充分的利用IO资源,但是也给我们带来了新的问题。
当多个进程使用同一份数据资源的时候,就会引发数据安全或顺序混乱问题。
多进程抢占输出资源
import os
import time
import random
from multiprocessing import Process
def work(n):
print('%s: %s is running' %(n,os.getpid()))
time.sleep(random.random())
print('%s:%s is done' %(n,os.getpid()))
if __name__ == '__main__':
for i in range(3):
p=Process(target=work,args=(i,))
p.start()
执行输出:
1: 16548 is running
0: 1448 is running
2: 1096 is running
2:1096 is done
0:1448 is done
1:16548 is done
看输出结果,都是乱的。
如果想有序的执行,先run,再done,怎么办?
需要用到锁
import os
import time
import random
from multiprocessing import Lock
from multiprocessing import Process
def work(n,lock):
lock.acquire() #取得锁
print('%s: %s is running' %(n,os.getpid()))
time.sleep(random.random())
print('%s:%s is done' %(n,os.getpid()))
lock.release() #释放锁
if __name__ == '__main__':
lock = Lock() #创建锁
for i in range(5):
p=Process(target=work,args=(i,lock))
p.start()
执行输出:
0: 17468 is running
0:17468 is done
2: 16688 is running
2:16688 is done
1: 15984 is running
1:15984 is done
3: 15828 is running
3:15828 is done
4: 18156 is running
4:18156 is done
从结果上来看,结果就比较整齐了。先run,再done。结果是无序的
#创建锁 mutex = threading.Lock() #锁定 mutex.acquire([timeout])#timeout是超时时间 #释放 mutex.release() 其中,锁定方法acquire可以有一个超时时间的可选参数timeout。如果设定了timeout,则在超时后通过返回值可以判断是否得到了锁,从而可以进行一些其他的处理。