## 什么是协程?
- 使用单线程 从程序的角度去实现并发执行
- 协程是一种用户态的轻量级线程,即协程是由用户程序自己控制调度的。
## 目录
[TOC]
## 协程模块
### 0x01:greenlet模块
- - 如果我们在单个线程内有 `20` 个任务,要想实现在多个任务之间切换,使用yield生成器的方式过于麻烦(需要先得到初始化一次的生成器,然后再调用 `send`。。。非常麻烦),而使用 `greenlet` 模块可以非常简单地实现这20个任务直接的切换
- 由于 `greenlet` 模块不能实现自动检测IO操作,所以这里我们重点讲 `gevent` 模块
### 0x02:gevent模块
- 异步执行任务,自动检测IO操作,自动切换
- `gevent` 中用到的主要模式是 `Greenlet`, 它是以C扩展模块形式接入 `Python` 的轻量级协程。
- `Greenlet` 全部运行在主程序操作系统进程的内部,但它们被协作式地调度。
- 例 :结合 `gevent` 模块下的子模块 `monkey`,实现自动检测代码中的IO操作,并且自动切换 `gevent` 定义的任务
```python
from gevent import monkey;monkey.patch_all()
import gevent
import time
def eat(name):
print('%s eat 1' % name)
time.sleep(3)
print('%s eat 2' % name)
def play(name):
print('%s play 1' % name)
time.sleep(4)
print('%s play 2' % name)
start = time.time()
g1=gevent.spawn(eat, 'egon') # 将函数添加到gevent任务列表
g2=gevent.spawn(play, 'alex')
# g1.join()
# g2.join()
gevent.joinall([g1, g2]) # 代替单个join操作
stop = time.time()
print(stop-start)
start = time.time()
g1=gevent.spawn(eat, 'egon') # 将函数添加到gevent任务列表
g2=gevent.spawn(play, 'alex')
# g1.join()
# g2.join()
gevent.joinall([g1, g2]) # 代替单个join操作
stop = time.time()
print(stop-start)
```
运行结果
```
egon eat 1
alex play 1
egon eat 2
alex play 2
4.006288051605225
```
### 0x03:单线程下实现并发socket通讯
服务端代码
```python
#基于gevent实现
from gevent import monkey,spawn;monkey.patch_all()
from socket import *
def communicate(conn):
while True:
try:
data=conn.recv(1024)
if not data:break
conn.send(data.upper())
except ConnectionResetError:
break
conn.close()
def server(ip,port):
server = socket(AF_INET, SOCK_STREAM)
server.bind((ip,port))
server.listen(5)
while True:
conn, addr = server.accept()
spawn(communicate,conn)
server.close()
if __name__ == '__main__':
g=spawn(server,'127.0.0.1',8090)
g.join()
```
客户端代码
```python
from socket import *
from threading import Thread,currentThread
def client():
client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8090))
while True:
client.send(('%s hello' %currentThread().getName()).encode('utf-8'))
data=client.recv(1024)
print(data.decode('utf-8'))
client.close()
if __name__ == '__main__':
for i in range(500):
t=Thread(target=client)
t.start()
```

【Python并发编程】协程篇