zoukankan      html  css  js  c++  java
  • Python学习笔记Day11

    1. 协程:协程是一种用户态的轻量级线程。

    • 协程的好处

      1. 无需线程上下文切换的开销
      2. 无需原子操作锁定及同步的开销
      3. 方便切换控制流,简化编程模型
      4. 高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理。
    • 协程的缺点

      1. 无法利用多核:本质是单线程,它不能同时将单个CPU的多个核用上.
        协程需要和进程配合才能运行在多CPU上,一般都没有这个必要,除非是cpu密集型应用。
      2. 进行阻塞(Blocking)操作(如IO时)会阻塞掉整个程序

    简单协程:yield__next__()

    greenlet 协程,手动切换

    # 手动协程切换
    from greenlet import greenlet
    def test1():
        print(12)
        gr2.switch()    # 切换到协程gr2
        print(34)
        gr2.switch()
    def test2():
        print(56)
        gr1.switch()    # 切换到协程gr1
        print(78)
    
    
    gr1 = greenlet(test1)  # 启动一个协程
    gr2 = greenlet(test2)
    gr1.switch()    # 切换到协程gr1
    

    gevent 自动切换协程,是greenlet的封装

    # 自动协程切换
    import gevent
    
    def foo():
        print('Running in foo')
        gevent.sleep(2)  # 模仿io切换,切换出去,2s后io完成并切回来才执行
        print('Explicit context switch to foo again')
    def bar():
        print('Explicit精确的 context to bar')
        gevent.sleep(1)
        print('Implicit context switch back to bar')
    def func3():
        print("running func3 ")
        gevent.sleep(0)
        print("running func3  again ")
    
    gevent.joinall([    # 相当于pool进程池
        gevent.spawn(foo),  # 生成gevent协程
        gevent.spawn(bar),
        gevent.spawn(func3),
    ])
    

    2. 简单爬虫

    from urllib import request
    import gevent,time
    from gevent import monkey
    monkey.patch_all()  # 把当前程序的所有的io操作给我单独的做上标记 urllib要进行io操作
    
    def f(url):
        print('GET: %s' % url)
        resp = request.urlopen(url)     # 请求网页
        data = resp.read()  # 读取结果
        print('%d bytes received from %s.' % (len(data), url))
    
    # 同步,串行
    urls = ['https://www.python.org/',
            'https://www.ithome.com/',
            'https://github.com/' ]
    time_start = time.time()
    for url in urls:
        f(url)  # 批量爬虫
    print("同步cost",time.time() - time_start)
    async_time_start = time.time()
    
    # 异步,并行
    gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.baidu.com/'),
        gevent.spawn(f, 'https://github.com/'),
    ])
    print("异步cost",time.time() - async_time_start)
    

    3.事件驱动模型:

    1. 有一个事件(消息)队列;
    2. 鼠标按下时,往这个队列中增加一个点击事件(消息);
    3. 有个循环,不断从队列取出事件,根据不同的事件,调用不同的函数,如onClick()、onKeyDown()等;
    4. 事件(消息)一般都各自保存各自的处理函数指针,这样,每个消息都有独立的处理函数;
    5. 事件处理完后会回调返回一个信号,继续中断前的任务。

    4.io模式:

    • 阻塞io:遇到io阻塞,等待返回信号,然后将数据从内核拷贝到用户空间
    • 非阻塞io:不断发送io请求
    • io多路复用:多路socket同时请求,有信号返回,三种:selec、poll、epoll,必须非阻塞才能多路复用
    • 信号驱动io
    • 异步io:请求后不等待,io准备好直接拷贝数据到用户空间,然后才通知用户

    5.select IO多路复用

    select模拟socketserver

    6.selector 模块:默认用epoll,如果系统没有epoll就用select

    import selectors
    import socket
    
    sel = selectors.DefaultSelector()   # 实例selector对象
    
    def accept(sock, mask):
        conn, addr = sock.accept()  # Should be ready
        print('accepted', conn, 'from', addr,mask)
        conn.setblocking(False)     # 设置非阻塞
        sel.register(conn, selectors.EVENT_READ, read)  # 新连接再活动时注册read回调函数,处理活动数据
    
    def read(conn, mask):
        data = conn.recv(1024)  # Should be ready
        if data:
            print('echoing', repr(data), 'to', conn)
            conn.send(data)  # Hope it won't block
        else:
            print('closing', conn)
            sel.unregister(conn)
            conn.close()
    
    sock = socket.socket()
    sock.bind(('localhost', 9999))
    sock.listen(100)
    sock.setblocking(False)
    sel.register(sock, selectors.EVENT_READ, accept)    # 新连接注册accept回调函数,创建连接
    
    while True:
        events = sel.select()  # 默认io阻塞,有活动连接就返回活动的连接列表
        for key, mask in events:
            callback = key.data  # 就是accept或者read
            callback(key.fileobj, mask)  # key.fileobj =  fd文件句柄(r)
    

    7. RabbitMQ 消息队列,可实现任意进程间的消息传递,实质上是一个socket的封装

    py 进程queue 可允许父进程与子进程间queue访问,或子进程之间,进程间数据传递
    未学完,需要另外安装
    https://www.cnblogs.com/alex3714/articles/5248247.html

    8. Redis 实现数据的共享,数据在内存,实质上也是一个socket的封装

    需要另外安装

  • 相关阅读:
    C语言不进行类型检查 和函数能够不进行前向声明
    EventBus 《二》 Android EventBus的简单使用
    android开发之SnackBar的使用
    iOS语音播放之切换听筒和扬声器
    使用NSURLConnection的网络请求与封装
    Mina Basics 02-基础
    Mina Basics 02-基础
    jquery移除事件,绑定事件,触发事件
    jquery移除事件,绑定事件,触发事件
    jquery移除事件,绑定事件,触发事件
  • 原文地址:https://www.cnblogs.com/JeromeLong/p/13237076.html
Copyright © 2011-2022 走看看