协程

1.携程的概念

# 进程 资源分配的最小单位
# 线程 CPU执行的最小单位

# 只要是线程里的代码 就都被CPU执行就行
# 线程是由 操作系统 调度,由操作系统负责切换的
# 协程:
   # 用户级别的,由我们自己写的python代码来控制切换的
   # 是操作系统不可见的
# 在Cpython解释器下 - 协程和线程都不能利用多核,都是在一个CPU上轮流执行
   # 由于多线程本身就不能利用多核
   # 所以即便是开启了多个线程也只能轮流在一个CPU上执行
   # 协程如果把所有任务的IO操作都规避掉,只剩下需要使用CPU的操作
   # 就意味着协程就可以做到提高CPU利用率的效果
# 多线程和协程
   # 线程 切换需要操作系统,开销大,操作系统不可控,给操作系统的压力大
       # 操作系统对IO操作的感知更加灵敏
   # 协程 切换需要python代码,开销小,用户操作可控,完全不会增加操作系统的压力
       # 用户级别能够对IO操作的感知比较低

2.切换问题

# 协程 :能够在一个线程下的多个任务之间来回切换,那么每一个任务都是一个协程
# 两种切换方式
   # 原生python完成   yield asyncio
   # C语言完成的python模块 greenlet gevent

greenlet
import time
from  greenlet import greenlet

def eat():
   print('wusir is eating')
   time.sleep(0.5)
   g2.switch()
   print('wusir finished eat')

def sleep():
   print('小马哥 is sleeping')
   time.sleep(0.5)
   print('小马哥 finished sleep')
   g1.switch()

g1 = greenlet(eat)
g2 = greenlet(sleep)
g1.switch()

3.gevent模块

import time
print('-->',time.sleep)
import gevent
from gevent import monkey
monkey.patch_all()
def eat():
   print('wusir is eating')
   print('in eat: ',time.sleep)
   time.sleep(1)
   print('wusir finished eat')

def sleep():
   print('小马哥 is sleeping')
   time.sleep(1)
   print('小马哥 finished sleep')

g1 = gevent.spawn(eat)  # 创造一个协程任务
g2 = gevent.spawn(sleep)  # 创造一个协程任务
g1.join()   # 阻塞 直到g1任务完成为止
g2.join()   # 阻塞 直到g1任务完成为止


import time
import gevent
from gevent import monkey
monkey.patch_all()
def eat():
   print('wusir is eating')
   time.sleep(1)
   print('wusir finished eat')

def sleep():
   print('小马哥 is sleeping')
   time.sleep(1)
   print('小马哥 finished sleep')

# g1 = gevent.spawn(eat) # 创造一个协程任务
# g3 = gevent.spawn(eat) # 创造一个协程任务
# g2 = gevent.spawn(sleep) # 创造一个协程任务
# # g1.join()   # 阻塞 直到g1任务完成为止
# # g2.join()   # 阻塞 直到g1任务完成为止
# gevent.joinall([g1,g2,g3])
g_l = []
for i in range(10):
   g = gevent.spawn(eat)
   g_l.append(g)
gevent.joinall(g_l)

import time
import gevent
from gevent import monkey
monkey.patch_all()
def eat():
   print('wusir is eating')
   time.sleep(1)
   print('wusir finished eat')
   return 'wusir***'

def sleep():
   print('小马哥 is sleeping')
   time.sleep(1)
   print('小马哥 finished sleep')
   return '小马哥666'

g1 = gevent.spawn(eat)
g2 = gevent.spawn(sleep)
gevent.joinall([g1,g2])
print(g1.value)
print(g2.value)

4.asyncio模块

```python
import asyncio

# 起一个任务
async def demo(): # 协程方法
print('start')
await asyncio.sleep(1) # 阻塞
print('end')

loop = asyncio.get_event_loop() # 创建一个事件循环
loop.run_until_complete(demo()) # 把demo任务丢到事件循环中去执行

# 启动多个任务,并且没有返回值
async def demo(): # 协程方法
print('start')
await asyncio.sleep(1) # 阻塞
print('end')

loop = asyncio.get_event_loop() # 创建一个事件循环
wait_obj = asyncio.wait([demo(),demo(),demo()])
loop.run_until_complete(wait_obj)

# 启动多个任务并且有返回值
async def demo(): # 协程方法
print('start')
await asyncio.sleep(1) # 阻塞
print('end')
return 123

loop = asyncio.get_event_loop()
t1 = loop.create_task(demo())
t2 = loop.create_task(demo())
tasks = [t1,t2]
wait_obj = asyncio.wait([t1,t2])
loop.run_until_complete(wait_obj)
for t in tasks:
print(t.result())

# 谁先回来先取谁的结果
import asyncio
async def demo(i): # 协程方法
print('start')
await asyncio.sleep(10-i) # 阻塞
print('end')
return i,123

async def main():
task_l = []
for i in range(10):
task = asyncio.ensure_future(demo(i))
task_l.append(task)
for ret in asyncio.as_completed(task_l):
res = await ret
print(res)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

import asyncio

async def get_url():
reader,writer = await asyncio.open_connection('www.baidu.com',80)
writer.write(b'GET / HTTP/1.1 HOST:www.baidu.com Connection:close ')
all_lines = []
async for line in reader:
data = line.decode()
all_lines.append(data)
html = ' '.join(all_lines)
return html

async def main():
tasks = []
for url in range(20):
tasks.append(asyncio.ensure_future(get_url()))
for res in asyncio.as_completed(tasks):
result = await res
print(result)


if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(main()) # 处理一个任务


# python原生的底层的协程模块
# 爬虫 webserver框架
# 题高网络编程的效率和并发效果
# 语法
# await 阻塞 协程函数这里要切换出去,还能保证一会儿再切回来
# await 必须写在async函数里,async函数是协程函数
# loop 事件循环
# 所有的协程的执行 调度 都离不开这个loop
```

原文地址:https://www.cnblogs.com/usherwang/p/13054206.html