zoukankan      html  css  js  c++  java
  • 协程

    线程中的多个任务,其中的每一个任务都可以成为一个协程,每一个协程都可以在一条线程中任意的切换

    原理:

    多个线程处理多个任务就相当于把所有任务中的空隙都填满的一个单线程

    优势:

    1.不必做线程之间的切换了

    2.能够让一个线程看起来尽量忙碌,骗过操作系统,让程序不进入阻塞队列

    3.线程是操作系统中能被CPU调度的最小单位,操作系统只能调度到线程,如果多个任务在同一条线程上执行,而不是开启多个线程执行,能减轻操作系统的负担

    在其他编译型语言中,由于多线程可以利用多核,协程的概念被弱化了,对于CPython,多线程也不能利用多核,所有协程的概念变得至关重要

    特点:

    不能利用多核

    用户级的概念,操作系统不可见

    协程不存在数据安全问题(不涉及操作系统的调度,不会出现数据不安全)

    能够从程序级别感知到的IO操作:网络,时间

    在网络操作情况选,协程的效率比线程高

    在多个任务之间切换

    生成器本身就是一个协程

    async 使用yield关键字实现了规避IO的操作

    tornado框架也是利用yield

    即便是程序级别,yield切换也会带来一些时间开销

    def consumer():        
        while True:           # 必须生产者先生产 ,再由消费者进行消费
            goods = yield
            print(goods)
    
    def producer():
        c = consumer()      #产生生成器
        next(c)
        for i in range(10):
            c.send('土豆%s'%i)    #传参数给goods
    
    producer()
    import time
    from greenlet import greenlet
    def eat():
        print('start eating')
        g2.switch()          # 切换执行g2协程
        time.sleep(1)
        print('eating finished')
    
    def sleep():
        print('sleep eating')
        time.sleep(1)
        print('sleep finished')
        g1.switch()          #切换执行g1协程
    
    g1 = greenlet(eat)       #创建协程对象
    g2 = greenlet(sleep)     #创建协程对象
    g1.switch()              #执行
    
    结果:
    start eating
    sleep eating
    sleep finished
    eating finished
    switch切换

    gevent

    内部使用了greenlet的切换机制,实现了遇到IO自动进行切换

    from threading import currentThread
    from gevent import monkey
    monkey.patch_all()
    import time
    import gevent
    
    def eat():
        print('start eating',currentThread())    # 打印线程名  DummyThread-1  伪线程
        time.sleep(1)
        print('eating finished')
    
    def sleep():
        print('sleep eating',currentThread())     # 打印线程名  DummyThread-1  伪线程
        time.sleep(1)
        print('sleep finished')
    
    # for i in range(5):
    #     g1 = gevent.spawn(eat)
    #     g2 = gevent.spawn(sleep)
    # g1.join()              # 如果没有join,来不及运行函数内的代码  主代码就会运行结束
    # g2.join()
    
    #join的另一种用法
    g_l = []
    for i in range(5):
        g1 = gevent.spawn(eat)
        g2 = gevent.spawn(sleep)
        g_l.append(g1)
        g_l.append(g2)
    gevent.joinall(g_l)

    协程实现socketserver

    from gevent import monkey
    monkey.patch_all()
    import socket
    import gevent
    
    def talk(conn):
        while True:
            msg = conn.recv(1024).decode('utf-8')
            conn.send( msg.upper().encode('utf-8'))
    
    server = socket.socket()
    server.bind(('127.0.0.1',9004))
    server.listen()
    while True:
        conn,addr = server.accept()
        g = gevent.spawn(talk,conn)
    客户端
    import socket
    import threading
    
    def client():
        client = socket.socket()
        client.connect(('127.0.0.1',9004))
        while True:
            client.send(b'hello')
            msg = client.recv(1024)
            print(msg)
    
    for i in range(500):
        threading.Thread(target=client).start()   # 实现500个线程并发
    客户端

    两个协程模块:

    gevent   基于greenlet   使用更方便,性能相对低

    asyncio  基于yield     性能更好

    协程爬虫(gevent应用)

    # gevent处理问题很简便,直接扔给spawn就行了
    
    from gevent import monkey
    monkey.patch_all()
    import gevent
    import time
    from urllib import request
    
    def get_page(url_t):
        ret = request.urlopen(url_t[0])
        content = ret.read()
        with open(url_t[1]+'_new','wb') as f:
            f.write(content)
    url_lst = [
        ('http://www.sogou.com','sogou'),
        ('http://www.baidu.com','baidu'),
        ('http://www.douban.com','douban'),
        ('http://www.cnblogs.com','cnblogs1'),
        ('http://www.cnblogs.com/Eva-J','cnblogs2'),
        ('http://www.cnblogs.com/Eva-J/articles/8324673.html','cnblogs3'),
        ('http://www.cnblogs.com/Eva-J/p/7277026.html','cnblogs4'),
        ('http://www.JD.com','jd'),
        ('http://www.taobao.com','tb')
    ]
    start = time.time()
    g_l = []
    for url_t in url_lst:
        g = gevent.spawn(get_page,url_t)
        g_l.append(g)
    gevent.joinall(g_l)
    print(time.time() - start)
  • 相关阅读:
    【学习笔记】【C语言】注释
    【学习笔记】【C语言】标识符
    【学习笔记】【C语言】关键字
    【学习笔记】【C语言】第一个C程序
    【学习笔记】Xcode常见设置
    【学习笔记】Mac OS X系统介绍
    【学习笔记】虚拟机安装Mac系统
    javascript 对象 + 数组
    SpringMVC实现原理及详解
    javaweb国际化
  • 原文地址:https://www.cnblogs.com/sandy-123/p/10478242.html
Copyright © 2011-2022 走看看