一、协程
进程:启动多个进程 进程之间是由操作系统负责线程:启动多个线程 真正被cpu执行的最小单位实际是线程 开启一个线程 创建一个线程 需要寄存器 堆栈协程:本质上是一个线程,能在多个任务之间切换来节省一些IO时间 协程中任务之间的切换也消耗时间,但是开销远远小于进程线程之间的切换都是实现并发的手段
真正的协程模块就是使用greenlet模块完成的切换
rom greenlet import greenlet
def eat():
print("eating start")
g2.switch()
print("eating end")
g2.switch()
def play():
print("playing start")
g1.switch()
print("playing end")
g1 = greenlet(eat)
g2 = greenlet(play)
g1.switch()
二、gevent模块
"""一般最大限度可以开: 进程 线程 协程 5 20 500 最多可以实现5w个并发"""
注意gevent模块没办法自动识别time.sleep等io情况需要你手动再配置一个参数
from gevent import monkey;monkey.patch_all() # 识别所有IO操作,在导入gevent模块之前
import gevent
import time
import threading
def eat():
print(threading.current_thread().getName()) #协程其实就是假的线程
print("eating start")
time.sleep(1)
print("eating end")
def play():
print(threading.current_thread().getName())
print("playing start")
time.sleep(1)
print("playing end")
g1 = gevent.spawn(eat) #(检测是否有阻塞)
g2 = gevent.spawn(play)
g1.join()
g2.join()
# 进程和线程的任务切换由操作系统完成
# 协程任务之间的切换由程序(代码)完成,只要遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发效果

from gevent import monkey;monkey.patch_all()
import time
import gevent
def task():
time.sleep(1)
print(123456)
def sync():
for i in range(10):
task()
def async():
g_lis = []
for i in range(20):
g = gevent.spawn(task)
g_lis.append(g)
# for g in g_lis:g.join()
gevent.joinall(g_lis) # 接收可迭代对象
sync()
async()
协程在运行过程中,先集体等待一秒,然后一次全部打印出来"""
三、协程应用
小爬虫:

from gevent import monkey;
monkey.patch_all()
import requests
import gevent
def get_url(url):
res = requests.get(url)
print(res)
content = res.content.decode("utf8")
# print(content)
return len(content)
g1 = gevent.spawn(get_url, "http://www.baidu.com")
g2 = gevent.spawn(get_url, "http://www.sogou.com")
g3 = gevent.spawn(get_url, "http://www.taobao.com")
g4 = gevent.spawn(get_url, "http://www.hao123.com")
g5 = gevent.spawn(get_url, "http://www.cnblogs.com")
gevent.joinall([g1, g2, g3, g4, g5])
print(g1.value)
print(g2.value)
print(g3.value)
print(g4.value)
print(g5.value)
四、基于协程socket高并发通信
#服务端
import socket
from gevent import monkey;monkey.patch_all()
import gevent
server = socket.socket()
server.bind(("127.0.0.1", 8080))
server.listen(5)
def chat(conn):
conn.send(b"hello")
print(conn.recv(1024).decode("utf8"))
conn.close()
while True:
conn, addr = server.accept()
g1 = gevent.spawn(chat, conn)
server.close()
客户端
import socket
client = socket.socket()
client.connect(("127.0.0.1", 8080))
msg = client.recv(1024)
print(msg)
ret = input(">>>>>>>>:").encode("utf8")
client.send(ret)
client.close()
五、IO模型
五种 IO Model: blocking IO 阻塞IO nonblocking IO 非阻塞IO IO multiplexing IO多路复用 signal driven IO 信号驱动IO asynchronous IO 异步IO当一个read操作发生时:1.等待数据准备 2.将数据从内核(kernel)拷贝到进程中同步:提交一个任务之后等待这个任务执行完毕异步:只管提交任务,不等待这个任务执行完毕就可以做其他事情阻塞:recv(等待接收字节数据copy) recvfrom(接收) accept(等待别人给你打电话)阻塞: 线程 运行状态 》》》》阻塞状态》》》》》》》》就绪非阻塞:在非阻塞IO中,用户进程其实是要不断的主动询问操作系统数据准备好了没"""非阻塞IO模型:
#服务端
import socket
server = socket.socket() # 拿到手机
server.bind(("127.0.0.1", 8080)) # 绑定IP和端口
server.listen()
server.setblocking(False) # 变成非阻塞模式
conn_l = [] # 用来存储所有来请求server端的conn连接
del_conn = [] # 用来存储所有已经断开与server端连接的conn
while True:
try:
conn, addr = server.accept() # 非阻塞,但是没人连接会报错
print("建立连接了")
conn_l.append(conn)
except BlockingIOError:
for con in conn_l:
try:
msg = con.recv(1024) # 非阻塞 没人发消息会报错
if msg == b"":
del_conn.append(con)
continue
print(msg)
con.send(b"byebye")
except BlockingIOError:
pass
for con in del_conn:
conn_l.remove(con)
del_conn.clear()
#客户端
import socket
import time
client = socket.socket()
client.connect(("127.0.0.1", 8080))
while True:
client.send(b"hello")
client.close()
