zoukankan      html  css  js  c++  java
  • 三十二、协程与IO模型

    一、协程

    进程:启动多个进程 进程之间是由操作系统负责
    线程:启动多个线程 真正被cpu执行的最小单位实际是线程
    开启一个线程 创建一个线程 需要寄存器 堆栈
    协程:本质上是一个线程,能在多个任务之间切换来节省一些IO时间
    协程中任务之间的切换也消耗时间,但是开销远远小于进程线程之间的切换
    都是实现并发的手段

    真正的协程模块就是使用greenlet模块完成的切换
    rom greenlet import greenlet
    
    
    def eat():
        print("eating start")
        g2.switch()
        print("eating end")
        g2.switch()
    
    
    def play():
        print("playing start")
        g1.switch()
        print("playing end")
    
    
    g1 = greenlet(eat)
    g2 = greenlet(play)
    g1.switch()

    二、gevent模块

    """一般最大限度可以开:
    进程 线程 协程
    5 20 500 最多可以实现5w个并发"""
    
    
    注意gevent模块没办法自动识别time.sleep等io情况
    需要你手动再配置一个参数

    from
    gevent import monkey;monkey.patch_all() # 识别所有IO操作,在导入gevent模块之前 import gevent import time import threading def eat(): print(threading.current_thread().getName()) #协程其实就是假的线程 print("eating start") time.sleep(1) print("eating end") def play(): print(threading.current_thread().getName()) print("playing start") time.sleep(1) print("playing end") g1 = gevent.spawn(eat) #(检测是否有阻塞) g2 = gevent.spawn(play) g1.join() g2.join() # 进程和线程的任务切换由操作系统完成 # 协程任务之间的切换由程序(代码)完成,只要遇到协程模块能识别的IO操作的时候,程序才会进行任务切换,实现并发效果
    from gevent import monkey;monkey.patch_all()
    import time
    import gevent
    
    def task():
        time.sleep(1)
        print(123456)
    
    
    def sync():
        for i in range(10):
            task()
    
    def async():
        g_lis = []
        for i in range(20):
            g = gevent.spawn(task)
            g_lis.append(g)
        # for g in g_lis:g.join()
        gevent.joinall(g_lis)  # 接收可迭代对象
    
    sync()
    async()
    协程在运行过程中,先集体等待一秒,然后一次全部打印出来"""
    协程,同步 异步的对比

    三、协程应用

    小爬虫:

    from gevent import monkey;
    
    monkey.patch_all()
    import requests
    import gevent
    
    
    def get_url(url):
        res = requests.get(url)
        print(res)
        content = res.content.decode("utf8")
        # print(content)
        return len(content)
    
    
    g1 = gevent.spawn(get_url, "http://www.baidu.com")
    g2 = gevent.spawn(get_url, "http://www.sogou.com")
    g3 = gevent.spawn(get_url, "http://www.taobao.com")
    g4 = gevent.spawn(get_url, "http://www.hao123.com")
    g5 = gevent.spawn(get_url, "http://www.cnblogs.com")
    gevent.joinall([g1, g2, g3, g4, g5])
    print(g1.value)
    print(g2.value)
    print(g3.value)
    print(g4.value)
    print(g5.value)
    View Code

    四、基于协程socket高并发通信

    #服务端
    import socket
    from gevent import monkey;monkey.patch_all()
    import gevent
    
    server = socket.socket()
    server.bind(("127.0.0.1", 8080))
    server.listen(5)
    
    
    def chat(conn):
        conn.send(b"hello")
        print(conn.recv(1024).decode("utf8"))
        conn.close()
    
    
    while True:
        conn, addr = server.accept()
        g1 = gevent.spawn(chat, conn)
    
    server.close()
    客户端
    import socket
    
    client = socket.socket()
    client.connect(("127.0.0.1", 8080))
    
    msg = client.recv(1024)
    print(msg)
    ret = input(">>>>>>>>:").encode("utf8")
    client.send(ret)
    client.close()

    五、IO模型

    五种 IO Model:
    blocking IO 阻塞IO
    nonblocking IO 非阻塞IO
    IO multiplexing IO多路复用
    signal driven IO 信号驱动IO
    asynchronous IO 异步IO

    当一个read操作发生时:1.等待数据准备 2.将数据从内核(kernel)拷贝到进程中

    同步:提交一个任务之后等待这个任务执行完毕
    异步:只管提交任务,不等待这个任务执行完毕就可以做其他事情
    阻塞:recv(等待接收字节数据copy) recvfrom(接收) accept(等待别人给你打电话)
    阻塞: 线程 运行状态 》》》》阻塞状态》》》》》》》》就绪
    非阻塞:在非阻塞IO中,用户进程其实是要不断的主动询问操作系统数据准备好了没

    """
    非阻塞IO模型:
    #服务端
    import socket
    
    server = socket.socket()  # 拿到手机
    server.bind(("127.0.0.1", 8080))  # 绑定IP和端口
    server.listen()
    
    server.setblocking(False)  # 变成非阻塞模式
    conn_l = []  # 用来存储所有来请求server端的conn连接
    del_conn = []  # 用来存储所有已经断开与server端连接的conn
    while True:
        try:
            conn, addr = server.accept()  # 非阻塞,但是没人连接会报错
            print("建立连接了")
            conn_l.append(conn)
        except BlockingIOError:
            for con in conn_l:
                try:
                    msg = con.recv(1024)  # 非阻塞 没人发消息会报错
                    if msg == b"":
                        del_conn.append(con)
                        continue
                    print(msg)
                    con.send(b"byebye")
                except BlockingIOError:
                    pass
            for con in del_conn:
                conn_l.remove(con)
            del_conn.clear()
    #客户端
    import socket
    import time
    client = socket.socket()
    client.connect(("127.0.0.1", 8080))
    
    while True:
        client.send(b"hello")
    
    client.close()
     
  • 相关阅读:
    12
    11-常用模块
    10-异常处理
    C#程序关闭时怎么关闭子线程
    [转]Android加载图片堆栈溢出
    [转]JS弹出确认/取消对话框
    [整理]获取当前页面的网址
    C/C++多参数处理
    图标素材网站收集
    PHP "Warning: Unknown: failed to open stream: Permission denied in Unknown on line 0" 错误
  • 原文地址:https://www.cnblogs.com/wukai66/p/11359185.html
Copyright © 2011-2022 走看看