线程
cpython解释下的多个线程不能利用多核:规避了所有io操作的单线程
协程
是操作系统不可见的
协程本质是一条线程,多个任务在一条线程上来回切换,
利用协程这个概念实现的内容:来规避IO操作,就达到了我们将一条线程中的io操作降到最低的目的
import time
def func1():
print('start')
time.sleep(1)
print('end')
def func2():
print('start')
time.sleep(1)
print('end')
逻辑问题,先开func1 func1 sleep(I/O)操作的时候 执行func2中的代码 发现func2
也有sleep(I/O)操作可以再切到其他任务
什么时候回来:记录时间,睡一秒后再回来
切换并规避IO的两个模块
gevent模块:利用了greenlet底层模块完成切换+自动规避io的功能
asyncio模块:利用了 yield 底层语法完成的切换+自动规避io的功能
yield from去实现协程 send更好实现协程
在python中提供协程功能的关键字:async await
进程 数据隔离 数据不安全 操作系统级别 开销非常大 cpython 能利用多核
线程 数据共享 数据不安全 操作系统级别 开销小 cpython不能利用多核
一些和文件操作相关的io只有操作系统能感知到
协程 数据共享 数据安全(用户级别切换)更小 cpython不能利用多核 协程所有切换都基于用户
只有在用户级别能够感知到的io操作才会用写成模块来规避(网络操作,socket,请求网页,sleep)
用户级别的协程有什么好处?
减小操作系统的负担
一条线程如果开了多个协程,那么给操作系统的印象是线程很忙,这样能够争取一些时间片来被CPU执行
程序的效率就提高了
对于操作系统:python代码–》编译-字节码-解释–》二进制000011111
4cpu
进程 5个进程
线程 20个
协程 500个
520500=50000
协程的例子
from gevent import monkey
monkey.patch_all()
import gevent
import asyncio
import time
def func(): # 带有io操作的内容写在函数里,然后提交func给gevent
print('start func')
# gevent.sleep(1)
time.sleep(1)
print('end func')
g1 = gevent.spawn(func)
g2 = gevent.spawn(func)
g3 = gevent.spawn(func)
gevent.joinall([g1, g2, g3])
g1.join() # 阻塞直到协程g1任务执行结束
gevent.sleep(2)
基于gevent协程实现socket并发
server
from gevent import monkey
monkey.patch_all()
import socket
import gevent
def func(conn):
while True:
msg = conn.recv(1024).decode('utf-8')
MSG = msg.upper()
conn.send(MSG.encode('utf-8'))
sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
while True:
conn, _ = sk.accept()
gevent.spawn(func, conn)
client
import socket
import time
from threading import Thread
def client():
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
while True:
sk.send(b'hello')
msg = sk.recv(1024)
print(msg)
time.sleep(0.5)
for i in range(500):
Thread(target=client).start()
asynico模块
import socket
import time
from threading import Thread
def client():
sk = socket.socket()
sk.connect(('127.0.0.1', 9000))
while True:
sk.send(b'hello')
msg = sk.recv(1024)
print(msg)
time.sleep(0.5)
for i in range(500):
Thread(target=client).start()
asynico实现原理
# 协程的原理
# yield
# def func():
# print(123)
# yield
# print(456)
# g=func()
# next(g)#切出去
# next(g)#切回来
import time
def sleep(n):
print('start sleep')
yield time.time() + n
print('end sleep')
def func(n):
print(123)
gen = sleep(n)
yield from gen # yield vs yield from
print(456)
n = 1
g1 = func(n)
g2 = func(n)
ret1 = next(g1) # 切出去
ret2 = next(g2)
# print('--->',ret)
# time.sleep(ret-time.time())
# next(g) # 切回来
time_lst = {ret1: g1, ret2: g2}
print('--->', time_lst)
while time_lst:
min_time = min(time_lst)
time.sleep(min_time - time.time())
try:
next(time_lst[min_time])
except StopIteration:
pass
del time_lst[min_time]
# 网络编程:会起tcp协议,udp协议
# 并发编程 会起进程 线程 协程
# 概念 相关模块 最起码的启停机制