协程

协程

1.切换+保存状态:用yield实现

import time
def producer():
    g=consumer()
    next(g)
    for i in range(1000000):
        g.send(i)

def consumer():

    while True:
        n=yield


start=time.time()
producer()
stop=time.time()
print(stop-start)
切换+保存状态

2.greenlet模块

greenlet模块与yield一样都不能检测io然后自动切换,唯一的优点是比yield的切换方式方便

from greenlet import greenlet
def eat(name):
    print('%s eat 1'%name)
    p2.switch('alex')
    print('%s eat 2'%name)
    p2.switch()

def play(name):
    print('%s play 1'%name)
    p1.switch()
    print('%s play 2'%name)


p1=greenlet(eat)
p2=greenlet(play)
p1.switch('alex')
greenlet模块

3.协程

(1)协程:单线程下实现并发----遇到io切换,是一种用户态的轻量级线程,即是由用户程序自己控制单线程下任务的切换

(2)特点:

  • 只在一个单线程里实现并发
  • 修改共享数据不需要加锁
  • 用户程序里自己保存多个控制流的上下文栈
  • 一个协程遇到IO操作自动切换到其它线程(如何实现检测IO,yield、greenlet都无法实现,就用到gevent模块(select机制))

(3)gevent模块实现协程

from gevent import monkey;monkey.patch_all()
from threading import current_thread
import gevent,time
def eat():
    print('%s eat 1'%current_thread().getName())
    gevent.sleep(2)

    print('%s eat 2'%current_thread().getName())


def play():

    print('%s play 1'%current_thread().getName())

    gevent.sleep(1)
    print('%s play 2'%current_thread().getName())

start=time.time()
g1=gevent.spawn(eat,)
g2=gevent.spawn(play,)
gevent.joinall([g1,g2])
stop=time.time()
print(stop-start)
协程

(4)单线程并发爬页面

from gevent import monkey;monkey.patch_all()
import gevent
import requests
from threading import current_thread
def get(url):
    print('%s get %s' %(current_thread().getName(),url))
    response=requests.get(url)
    if response.status_code == 200:
        return {'url':len(response.text)}
        # print({'url':len(response.text)})


g1=gevent.spawn(get,'http://www.baidu.com')
g2=gevent.spawn(get,'http://www.python.org')
g3=gevent.spawn(get,'http://www.jd.com')

g1.join()
g2.join()
g3.join()

print(g1.value)
print(g2.value)
print(g3.value)
爬虫

(5)基于协程实现单线程下套接字通信

  • 服务端
from gevent import monkey;monkey.patch_all()
import gevent
from socket import *

print('start')

def connect(ip,port):
    server=socket(AF_INET,SOCK_STREAM)
    server.bind((ip,port))
    server.listen(5)
    while True:
        conn,addr=server.accept()
        print('%s:%s'%(addr[0],addr[1]))
        gevent.spawn(talk,conn,addr)

def talk(conn,addr):
    while True:
        try:
            data=conn.recv(1024)
            conn.send(data.upper())
            print('%s:%s  [%s]' % (addr[0], addr[1],data))
        except Exception:
            break

if __name__ == '__main__':
    connect('127.0.0.1',8080)
server
  • 客户端
from socket import *
from threading import Thread

def receive():
    s=socket()
    s.connect(('127.0.0.1',8080))


    while True:
        msg=input('>>:')
        if not msg:break
        s.send(msg.strip().encode('utf-8'))
        data=s.recv(1024)
        print(data.decode('utf-8'))

if __name__ == '__main__':
    p=Thread(target=receive)
    p.start()
client

 

posted @ 2017-10-22 18:30  星雨5213  阅读(65)  评论(0)    收藏  举报