• 协程


    一. 协程: 单线程实现并发(保存状态加切换)

    协程本质上就是一个线程,以前线程任务的切换是由操作系统控制的,
    遇到I/O自动切换,现在我们用协程的目的就是较少操作系统切换的开销
    (开关线程,创建寄存器、堆栈等,在他们之间进行切换等),
    在我们自己的程序里面来控制任务的切换。
    优点: 切换速度快 单线程内就可以实现并发的效果,最大限度利用CPU
    缺点: 无法利用多核,可以是一个程序开启多个进程,每个进程内开启多个线程,每个线程内开启协程
    特点:
    1)必须在只有一个单线程里实现并发
    2)修改共享数据不需加锁
    3)用户程序里自己保存多个控制流的上下文栈
    4)附加:一个协程遇到IO操作自动切换到其它协程
    (如何实现检测IO,yield、greenlet都无法实现,就用到了gevent模块(select机制))

    二. Greenlet
    使用greenlet完成切换
    from greenlet import greenlet
    g = greenlet(函数)
    g.swith() 切换 不能IO自动切换
    三. gevent
    g1 = gevent.spawn(函数1)
    g2 = gevent.spawn(函数2)
    g1.join() 等待g1结束,上面只是创建协程对象,join才是去执行
    g2.join() / 两步合并: gevent.joinall([g1,g2])
    g1.value 拿到函数1的返回值
    注意:
    要用gevent,需要将from gevent import monkey;monkey.patch_all()放到文件的开头
    四. 非阻塞IO
    server.setBlocking(False) # 将阻塞变为非阻塞 遇到原本应阻塞的会报错
    lst1 = [] 存放conn连接
    dic = {} 存放所有已经有了请求数据的conn连接
    try:
    会报错的原本应阻塞的程序
    except BlockingIOError:
    del_lst = []
    for conn in lst1:
    ret = 接收数据
    if not ret:
    conn.close()
    del_lst.append(conn) # 将断开连接的conn放在新列表中,准备删除
    dic[conn] = ret.upper() # 将接收的数据已字典的形式存入 准备发送数据用
    del_wlst = []
    for conn,data in dic.items():
    conn.send(data)
    del_wlst.append(conn)
    for conn in del_lst:
    lst1.remove(conn)
    for conn in del_wlst:
    dic.pop(conn)
    五. IO多路复用
    server.setBlocking(False) # 将阻塞变为非阻塞 遇到原本应阻塞的会报错
    # 存放所有有变化的连接对象,server/conn
    r_lst = [server]
    # 存放客户端发送过来的消息
    r_data = {}
    # 等待写对象
    w_lst = []
    # 存放要返回给客户端的消息
    w_dit = {}
    # # 被触发的(有动静的)套接字(服务器套接字)返回给了rl这个返回值里面
    r1, w1, x1 = select.select(r_lst, w_lst, [], 0.5)

    for sock in r1:
    if sock == server:
    conn, addr = sock.accept()
    r_lst.append(conn)
    else:
    try:
    试着接收数据
    sock.recv(1024)
    # 没有数据的时候,我们将这个连接关闭掉,并从监听列表中移除
    if not data:
    sock.close()
    r_lst.remove(sock)
    continue
    # 将接受到的客户端的消息保存下来
    r_data[sock] = data.decode("utf-8")
    # 将客户端连接对象和这个对象接收到的消息加工成返回消息,并添加到w_dit这个字典里面
    w_dit[sock] = data.upper()
    # 需要给这个客户端回复消息的时候,我们将这个连接添加到w_lst写监听列表中
    w_lst.append(sock)
    for sock in w1:
    sock.send(w_dit[sock])
    w_lst.remove(sock)
    w_dit.pop(sock)
  • 相关阅读:
    LeetCode 17. Letter Combinations of a Phone Number (电话号码的字母组合)
    Mordern Effective C++ --auto
    modern effective C++ -- Deducint Types
    基于锁的并发数据结构
    C++ 内存模型
    zlib 简单封装
    assert 实现分析
    Valgrind 快速入门
    kmp算法理解与记录
    make 要点简记
  • 原文地址:https://www.cnblogs.com/sophie99/p/9879613.html
Copyright © 2020-2023  润新知