一、协程

  • 又称微线程
  • 协程是一种用户态的轻量级的线程
  • 在单线程下实现的并发,例如:yield
    优点:
  • 无需线程上下文切换的开销
  • 无需原子操作锁定及同步的开销
  • 方便切换控制流,简化编程模型
  • 高并发,高扩展性,低成本:一个CPU可支持上万的协程
    缺点:
  • 无法利用多核资源
  • 进行阻塞操作会阻塞掉整个程序
import time,queue

def consumer(name):
    print('--->starting eating bun...')
    while True:
        new_bun = yield
        print("[%s] is eating bun %s" %(name,new_bun))

def producer():
    r = con.__next__()
    r = con2.__next__()
    n = 0
    while n < 5:
        n += 1
        con.send(n)
        con2.send(n)
        print("\033[32;1m[producer]\033[0m is making bun %s" %n)

if __name__ == '__main__':
    con = consumer("c1")
    con2 = consumer("c2")
    p = producer()

二、greenlet 手动切换

# Author:Li Dongfei

from greenlet import greenlet

def test1():
    print(12)
    gr2.switch()  #切换至gr2
    print(34)
    gr2.switch()

def test2():
    print(56)
    gr1.switch()
    print(78)

gr1 = greenlet(test1)  #启动一个协程
gr2 = greenlet(test2)
gr1.switch()  #切换至gr1

三、genent 自动切换

  • 遇到sleep自动切换
# Author:Li Dongfei
import gevent

def foo():
    print("Running in foo")
    gevent.sleep(2)
    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 func():
    print("in the func")
    gevent.sleep(0)
    print("in the func again")

gevent.joinall([
    gevent.spawn(foo),
    gevent.spawn(bar),
    gevent.spawn(func),
])
  • 协程并发爬网页
# Author:Li Dongfei

from gevent import monkey; monkey.patch_all()  #把当前程序所有的io操作单独做标记,让gevent识别
import gevent
from urllib.request import urlopen

def f(url):
    print('GET: %s' %url)
    resp = urlopen(url)
    data = resp.read()
    f = open("url.html", "wb")
    f.write(data)
    f.close()
    print('%d bytes received from %s.' %(len(data), url))

gevent.joinall([
    gevent.spawn(f, 'https://www.python.org'),
    gevent.spawn(f, 'https://www.github.com'),
    gevent.spawn(f, 'https://www.aliyun.com'),
])
  • 通过gevent实现单线程的多socket并发
  • server
# Author:Li Dongfei

import sys,socket,time,gevent
from gevent import socket,monkey
monkey.patch_all()

def server(port):
    s = socket.socket()
    s.bind(('localhost', port))
    s.listen(500)
    while True:
        cli, addr = s.accept()
        gevent.spawn(handle_request, cli)

def handle_request(conn):
    try:
        while True:
            data = conn.recv(1024)
            print("recv:", data)
            conn.send(data)
            if not data:
                conn.shutdown(socket.SHUT_WR)
    except Exception as ex:
        print(ex)
    finally:
        conn.close()

if __name__ == '__main__':
    server(8001)
  • client
# Author:Li Dongfei
import socket

HOST = 'localhost'
PORT = 8001

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
while True:
    msg = bytes(input(">>:"), encoding="utf-8")
    s.sendall(msg)
    data = s.recv(1024)
    print('Received', data)

s.close()

四、I/O模型

  • 阻塞
  • 非阻塞
  • I/O多路复用
  • 信号驱动
  • 异步
  • Python select socket server代码示例
# Author:Li Dongfei
import select, socket, sys, queue
server = socket.socket()
server.bind(('localhost', 9000))
server.listen(1000)
server.setblocking(False)  #设置为非阻塞

msg_dic = {}
inputs = [server,]
outputs = []

while True:
    readable, writeable, exceptional = select.select(inputs, outputs, inputs)
    print(readable,writeable,exceptional)
    for r in readable:
        if r is server:
            conn, addr = server.accept()
            print("new connect", addr)
            inputs.append(conn)
            msg_dic[conn] = queue.Queue()
        else:
            data = r.recv(1024)
            print("recv data",data)
            msg_dic[r].put(data)
            outputs.append(r)

    for w in writeable:
        data_to_clinet =msg_dic[w].get()
        w.send(data_to_clinet)
        outputs.remove(w)

    for e in exceptional:
        if e in outputs:
            outputs.remove(e)
        inputs.remove(e)
        del msg_dic[e]

五、selector模块

# Author:Li Dongfei
import selectors, socket

sel = selectors.DefaultSelector()

def accept(sock, mask):
    conn, addr = sock.accept()
    print('accepted', conn, 'from', addr)
    conn.setblocking(False)
    sel.register(conn, selectors.EVENT_READ, read)

def read(conn, mask):
    data = conn.recv(1024)
    if data:
        print('echoing', repr(data), 'to', conn)
        conn.send(data)
    else:
        print('closing', conn)
        sel.unregister(conn)
        conn.close()

sock = socket.socket()
sock.bind(('localhost', 9000))
sock.listen(1000)
sock.setblocking(False)
sel.register(sock, selectors.EVENT_READ, accept)

while True:
    events = sel.select()
    for key, mask in events:
        callback = key.data
        callback(key.fileobj, mask)

190221协程与IO模型的更多相关文章

  1. 并发编程 --进、线程池、协程、IO模型

    内容目录: 1.socket服务端实现并发 2.进程池,线程池 3.协程 4.IO模型 1.socket服务端实现并发 # 客户端: import socket client = socket.soc ...

  2. Cpython解释器下实现并发编程——多进程、多线程、协程、IO模型

    一.背景知识 进程即正在执行的一个过程.进程是对正在运行的程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有内容都 ...

  3. Python并发编程二(多线程、协程、IO模型)

    1.python并发编程之多线程(理论) 1.1线程概念 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程(流水线的工作需要电源,电源就相当于 ...

  4. 线程,协程,IO模型

    理论: 1.每创造一个进程,默认里面就有一个线程 2.进程是一个资源单位,而进程里面的线程才是CPU上的一个调度单位 3.一个进程里面的多个线程,是共享这个进程里面的资源的 4.线程创建的开销比进程要 ...

  5. 协程和IO模型

    协程 1.什么是协程 单线程实现并发 在应用程序里控制多个任务的切换+保存状态 优点: 应用程序级别速度要远远高于操作系统的切换 缺点: 多个任务一旦有一个阻塞没有切,整个线程都阻塞在原地 该线程内的 ...

  6. Python 协程、IO模型

    1.协程(单线程实现并发)2.I/0模型 2.1阻塞I/O 2.2非阻塞I/O 知识点一:协程 协程的目的:是想要在单线程下实现并发(并发看起来是同时运行的) 并发=多个任务间切换+保存状态(正常情况 ...

  7. python(40)- 进程、线程、协程及IO模型

    一.操作系统概念 操作系统位于底层硬件与应用软件之间的一层.工作方式:向下管理硬件,向上提供接口. 操作系统进行进程切换:1.出现IO操作:2.固定时间. 固定时间很短,人感受不到.每一个应用层运行起 ...

  8. 网络编程进阶:并发编程之协程、IO模型

    协程: 基于单线程实现并发,即只用一个主线程(此时可利用的CPU只有一个)情况下实现并发: 并发的本质:切换+保存状态 CPU正在运行一个任务,会在两种情况下切走去执行其他任务(切换有操作系统强制控制 ...

  9. day33_8_15 并发编程4,线程池与协程,io模型

    一.线程池 线程池是一个处理线程任务的集合,他是可以接受一定量的线程任务,并创建线程,处理该任务,处理结束后不会立刻关闭池子,会继续等待提交的任务,也就是他们的进程/线程号不会改变. 当线程池中的任务 ...

随机推荐

  1. No mapping found for HTTP request with URI [/jiaoyu/student/add] in DispatcherServlet with name 'SpringMVC'

    项目是使用spring MVC (1)在浏览器中访问,后台总报错: No mapping found for HTTP request with URI [/exam3/welcome] in Dis ...

  2. angularJS笔记之 服务

    angular的服务有五种 第一种 constant 一般作为一种常量的服务 不可更改 第二种 value 用来注册服务对象或函数 可更改 第三种 factory 创建和配置服务的最快捷方式.可更改 ...

  3. iis8不支持 aspnet_regiis.exe -iru 命令的解决办法

    服务器版的限制,我看你给的提示说也可以使用 dism.exe 命令行. C:\> DISM /Online /Enable-Feature /FeatureName:WCF-HTTP-Activ ...

  4. Python学习笔记_我的参考网址

    Python学习笔记, 下面记录网上搜到的可参考的网址: 一.关于Tkinter 1.Python3中tkinter模块使用方法详解 https://blog.csdn.net/Fighting_Bo ...

  5. django 1.8 官方文档翻译:13-12 验证器

    django 1.8 官方文档翻译:13-12 验证器 2015年09月20日 21:36:18 ApacheCN_飞龙 阅读数:639  https://blog.csdn.net/wizardfo ...

  6. Flask框架 之 上下文管理前戏

    偏函数 自动传递参数 import functools def index(a1,a2): return a1 + a2 # 原来的调用方式 # ret = index(1,23) # print(r ...

  7. Part5核心初始化_lesson4---关闭中断

    1.关闭cpsr寄存器里面的I(中断)和F(快速中断)位: 2.设置中断屏蔽寄存器. 针对2440: 这是中断处理过程,当有中断源(没有子中断源)来的时候,它会把这个中断记录在SRCPND里面:它还要 ...

  8. Entity Framework 6.0 Tutorials(6):Transaction support

    Transaction support: Entity Framework by default wraps Insert, Update or Delete operation in a trans ...

  9. C# Code 非常好的学习博客

    https://ardalis.com/how-to-become-master-writing-c-code

  10. Head First HTML与CSS、XHTML (中文版).(Elisabeth Freeman) PDF扫描版​

    面对那些晦涩的html书你不禁要问:“难道要成为专家之后才能读懂这些?”那么,你应该选择<head first html与css.xhtml(中文版)>真正来学习html.这本书对你来说, ...