一、socket并发
#服务端
import socket
from threading import Thread
server = socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
def communcate(conn):
while True:
try:
data = conn.recv(1024)
if not data: break
print(data)
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
while True:
conn,addr=server.accept()
print(addr)
t=Thread(target=communcate,args=(conn,))
t.start()
#客户端
import socket
client = socket.socket()
client.connect(('127.0.0.1', 8080))
while True:
info = input(">>>:").encode('utf-8')
if not info:continue
client.send(info)
data=client.recv(1024)
print(data.decode('utf-8'))
二、协程
协程:
进程:资源单位(车间)
线程:最小执行单位(流水线)
协程:单线程下实现并发
并发:看上去像同时执行就可以称之为并发
多道技术:
空间上的复用
时间上的复用
核心:切换+保存状态
协程:完全是我们高技术的人自己编出来的名词
通过代码层面自己监测io自己实现切换,让操作系统误认为
你这个线程没有io
切换+保存状态就一定能够提升你程序的效率吗?
不一定
当你的任务是计算密集型,反而会降低效率
如果你的任务是IO密集型,会提升效率
协程:单线程下实现并发
如果你能够自己通过代码层面监测你自己的io行为
并且通过代码实现切换+保存状态
串行执行纯计算操作
import time
def task1():
res =1
for i in range(1000000):
res+=i
def task2():
res=1
for i in range(1000000):
res*=i
stat=time.time()
task1()
task2()
stop =time.time()
print(stop-stat)
计算一段时间往上切,加上了来回切的时间
基于yiel保存状态,实现两个任务间来回切换,实现并发效果
yield并不能帮我们自动捕获到io行为才切换
import time
def task1():
res =1
for i in range(1000000):
res+=i
yield
def task2():
g=task1()
res=1
for i in range(1000000):
res*=i
next(g)
stat=time.time()
task2()
stop =time.time()
print(stop-stat)
三、gevent模块
一个spawn就是一个帮你管理任务的对象
gevent模块不能识别它本身以外的所有的IO行为比如(time.sleep)
from gevent import monkey;monkey.patch_all() #能够帮助我们识别所有的IO行为
from threading import current_thread
import gevent
import time
def eat():
print('%s eat 1'%current_thread().name)
# gevent.sleep(3)
time.sleep(3)
print('%s eat 2'%current_thread().name)
def play():
print('%s play 1'%current_thread().name)
# gevent.sleep(5)
time.sleep(5)
print('%s play 2'%current_thread().name)
g1 =gevent.spawn(eat) #异步提交
g2 =gevent.spawn(play)
print(current_thread().name)
g1.join()
g2.join()
四、进程池与线程池
1、为什么要用“池”:
池子是用来限制并发的任务数目,限制我们的计算机在一个自己承受的范围内去并发的执行任务
2、什么时候用进程池:
并发的任务属于计算密集型
3、什么时候用线程池:
并发的任务属于IO密集型
#进程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os,random
def task(x):
print('%s 接客'%os.getpid())
time.sleep(random.randint(2,3))
return x**2
if __name__ == '__main__':
p =ProcessPoolExecutor(max_workers=4) #默认开启进程数是cpu的核数
for i in range(20):
p.submit(task,i) #submit提交任务的方式,异步提交
#线程池
from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
import time,os,random
def task(x):
print('%s 接客'%x)
time.sleep(random.randint(2,3))
return x**2
if __name__ == '__main__':
p =ThreadPoolExecutor(4) #默认开启(线程数=cpu核数*5左右)
for i in range(20):
p.submit(task,i) #submit提交任务的方式,异步提交
五、单线程下实现并发
#服务端
from gevent import monkey;monkey.patch_all()
from gevent import spawn
import socket
def communicate(conn):
while True:
try:
data =conn.recv(1024)
if not data:break
print(data.decode('utf-8'))
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
def server():
server=socket.socket()
server.bind(('127.0.0.1',8080))
server.listen(5)
while True:
conn,addr = server.accept()
spawn(communicate,conn)
if __name__ == '__main__':
s1=spawn(server)
s1.join()
#客户端
from threading import Thread,current_thread
import socket
def client():
client=socket.socket()
client.connect(('127.0.0.1',8080))
n=1
while True:
data = '%s %s'%(current_thread().name,n)
n+=1
client.send(data.encode('utf-8'))
info=client.recv(1024)
print(info)
if __name__ == '__main__':
for i in range(500):
t=Thread(target=client)
t.start()