zoukankan      html  css  js  c++  java
  • 协程

    协和介绍

    协和:是单线程下的并发,又称微线程,纤程。协和是一种用户态的轻量级线程,即协和是由用户程序自己控制调度的。

    对于单线程下,我们不可避免程序出现io操作,但如果我们能在自己的程序中(即用户程序级别,而非操作系统级别)控制单线程下的多个任务能在一个任务遇到io阻塞 时就切换到另外一个任务去计算,这样就保证了该线程能够最大限度地处于就绪态,即都可以被cpu执行的状态,相当于我们在用户程序级别将自己的io操作最大限度地隐藏起来,从而可以迷惑操作系统,让其看到:该线程好像是一直在计算,Io比较少,从而更多的将cpu的执行权限分配给我们的线程。

    协和的本质就是在单线程下,由用户自己控制一个任务遇到io阻塞了就切换另一个任务去执行,以此来提升效率。

    1.python的线程属于内核级别的,即由操作系统控制调度(如单线程遇到io或者执行时间过长就会被迫交出cpu执行权限,切换其他线程运行)

    2.单线程内开启协和,一量遇到io,就会从应用程序级别(而非操作系统)控制切换,以此来提升效率(非io操作的切换与效率无关)

    协程优点:

     1.协和的切换开销更小,属于程序级别的切换,操作系统完全感知不到,因而更加轻量级

     2.单线程内就可以实现并发的效果,最大限度地利用cpu

    协和缺点:

     1.协和的本质是单线程下,无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协和

     2.协和指的是单个线程,因而一旦协程出现阻塞,将会阻塞整个线程

    yield实现函数间的切换:

    def func1():
        print(1)
        yield
        print(3)
        yield
    
    def func2():
        g = func1()
        next(g)
        print(2)
        next(g)
        print(4)
    
    func2()
    普切换
    def consumer():
        while True:
            n = yield
            print('消费了一个包子%s'%n)
    
    def producer():
        g = consumer()
        next(g)
        for i in range(10):
            print('生产了包子%s'%i)
            g.send(i)
    
    producer()
    生产者消费者模型

    Greenlet模块

    安装:pip3 install greenlet

    Gevent是一个第三方库,可以通过gevent实现并发同步或异步编程,在gevent中用到的主要模式是Greenet,它是以C扩展模块形式接入Python的轻量级协和。Greenlet全部运行在主程序操作系统进程的内部,但它们被协作式地调度。

    import time
    from greenlet import greenlet
    def eat1():
        print('吃鸡腿1')
        g2.switch()
        time.sleep(5)
        print('吃鸡腿2')
        g2.switch()
    
    def eat2():
        print('吃饺子1')
        g1.switch()
        time.sleep(3)
        print('吃饺子2')
    
    g1 = greenlet(eat1)
    g2 = greenlet(eat2)
    g1.switch()
    手动切换
    import gevent
    from threading import current_thread
    def func():
        print(current_thread().name)
        print(123)
        gevent.sleep(1)
        print(456)
    
    def func2():
        print(current_thread().name)
        print('wawawa')
        gevent.sleep(1)
        print('hahaha')
    
    g1 = gevent.spawn(func)
    g2 = gevent.spawn(func2)
    gevent.joinall([g1,g2])
    遇io自动切换

    Gevent同步与异步对比

    from gevent import monkey;monkey.patch_all()
    import time     # time socket urllib requests
    import gevent   # greenlet gevent在切换程序的基础上又实现了规避IO
    
    def task(args):
        time.sleep(1)
        print(args)
    
    def sync_func():   # 同步
        for i in range(10):
            task(i)
    
    def async_func(): # 异步
        g_l = []
        for i in range(10):
            g_l.append(gevent.spawn(task,i))   # 给写成任务传参数
        gevent.joinall(g_l)
    
    start = time.time()
    sync_func()
    print(time.time() - start)
    
    start = time.time()
    async_func()
    print(time.time() - start)
    同步异步

    协和应该:爬虫

    from gevent import monkey;monkey.patch_all()
    import time
    import gevent
    import requests
    def get_url(url):
        res = requests.get(url)
        print(url,res.status_code,len(res.text))
    
    url_lst =[
        'http://www.sohu.com',
        'http://www.baidu.com',
        'http://www.qq.com',
        'http://www.python.org',
        'http://www.cnblogs.com',
        'http://www.mi.com',
        'http://www.apache.org',
        'https://www.taobao.com',
        'http://www.360.com',
        'http://www.7daysinn.cn/'
    ]
    
    start = time.time()
    for url in url_lst:
        get_url(url)
    print(time.time() - start)
    爬虫
  • 相关阅读:
    json学习系列(1)-使用json所要用到的jar包下载
    Java 时间架构图
    时间纪元与时区介绍
    HTML5 Canvas 绘制库存变化折线
    HTML5 Canvas 笛卡尔坐标系转换尝试
    像孩童一样欣喜的看着自己的成长
    《老炮儿》结尾貌似历史上的一幕
    很多人还在守着金饭碗要饭
    还是用文本编辑器编程让人愉悦
    Node.js 网页爬虫再进阶,cheerio助力
  • 原文地址:https://www.cnblogs.com/tsboy/p/8432143.html
Copyright © 2011-2022 走看看