协程异步非阻塞

1、gevent. 在遇到io操作时会发生切换,切换gevent.joinall()中的gevent.spawn(a)去执行。

使用非gevent封装的sleep()时会发生阻塞

import gevent
import time

def a():
    print("begin a",time.time())
    time.sleep(1)
    print("end a ",time.time())

def b():
    print("begin b",time.time())
    time.sleep(1)
    print("end b ",time.time())

def c():
    print("begin c",time.time())
    time.sleep(1)
    print("end c ",time.time())

if __name__ == "__main__":
    gevent.joinall([
        gevent.spawn(a),
        gevent.spawn(b),
        gevent.spawn(c),]
    )

运行结果:
begin a 1466328299.3592122
end a  1466328300.3595576
begin b 1466328300.3595576
end b  1466328301.3598628
begin c 1466328301.3598628
end c  1466328302.3601925

2、使用gevent.sleep(1)时是非阻塞的。但是当然这个sleep(1)睡眠1秒还是要经历的,只是a在睡眠时可以切换到b或c去执行:

将上面的time.sleep(1)改为gevent.sleep(1)

gevent.sleep(1)

运行结果:
begin a 1466328564.0706365
begin b 1466328564.0891385
begin c 1466328564.089639
end a  1466328565.0892923
end c  1466328565.0907917
end b  1466328565.0907917

3、在文件最开始使用from gevent import monkey;monkey.patch_all() 可以使time.sleep(1)为非阻塞。这样就不用gevent的sleep(1)了。

4、gevent实现单线程socket允许同时多个连接同时发生数据。  也可以使用from gevent import socket,这样就不用使用monkey.patch_all()了。

简单示例代码:

# 服务器端
import gevent
import time
import socket
from gevent import monkey;monkey.patch_all()

def server(port):
    s = socket.socket()
    s.bind((‘127.0.0.1‘,port))
    s.listen(50)
    # s.setblocking(False)
    while True:
        conn, addr = s.accept()    # 接收客户端连接
        print("来了一个连接:",addr)
        gevent.spawn(handle_switch,conn)   # gevent.spawn()里的handle_switch()内部会非阻塞状态

def handle_switch(conn):
    while True:
        try:
            data = conn.recv(1024)        # 非阻塞,并不代表会往下执行,在这里而是发生切换。
        except ConnectionResetError as e:
            print(e)
            conn.close()
            break
        conn.send(data)                   # 非阻塞
        print("recv:",data.decode())
        if not data:
            conn.close()
            print("客户端正常关闭")
            break
if __name__ == "__main__":
    server(9001)

# 客户端
import socket

s = socket.socket()
s.connect((‘127.0.0.1‘,9001))

while True:
    data = input(">> ").strip()
    if data == "":
        continue
    if data == "q":
        s.close()
        break
    s.send(bytes(data,encoding="utf-8"))
    data = s.recv(1024)
    print("recv:",data.decode())

发起两个连接:

允许结果:

来了一个连接: (‘127.0.0.1‘, 55801)    # 第一个客户端连接
recv: asd
recv: asd
来了一个连接: (‘127.0.0.1‘, 55804)    # 第二个客户端连接
recv: sdfa
recv: asdg
recv: 1
recv: 1
recv: 2
recv: 2
recv: 1
recv: 2
recv:                                                # 客户端1断开连接,data为空
客户端正常关闭                                   # 客户端1正常断开,即客户端是s.close()的
recv: haha
recv:                                                # 客户端2断开连接,data为空
客户端正常关闭                                   # 客户端1正常断开,即客户端是s.close()的
来了一个连接: (‘127.0.0.1‘, 55820)     # 第三个客户端连接
recv: asd
[WinError 10054] 远程主机强迫关闭了一个现有的连接。       # 客户端3非正常连接,应该是被kill掉了进程,客户端发送rst包。
时间: 2024-12-22 21:54:42

协程异步非阻塞的相关文章

Python的异步编程[0] -> 协程[1] -> 使用协程建立自己的异步非阻塞模型

使用协程建立自己的异步非阻塞模型 接下来例子中,将使用纯粹的Python编码搭建一个异步模型,相当于自己构建的一个asyncio模块,这也许能对asyncio模块底层实现的理解有更大的帮助.主要参考为文末的链接,以及自己的补充理解. 完整代码 1 #!/usr/bin/python 2 # ============================================================= 3 # File Name: async_base.py 4 # Author: L

关于C10K、异步回调、协程、同步阻塞

最近到处在争论这些话题,发现很多人对一些基础的常识并不了解,在此发表一文做一下解释.此文未必能解答所有问题,各位能有一个大致的了解就好. C10K的由来 大家都知道互联网的基础就是网络通信,早期的互联网可以说是一个小群体的集合.互联网还不够普及,用户也不多.一台服务器同时在线100个用户估计 在当时已经算是大型应用了.所以并不存在什么C10K的难题.互联网的爆发期应该是在www网站,浏览器,雅虎出现后.最早的互联网称之为Web1.0, 互联网大部分的使用场景是下载一个Html页面,用户在浏览器中

爬虫必备—性能相关(异步非阻塞)

在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢. 1. 同步执行 1 import requests 2 3 def fetch_async(url): 4 response = requests.get(url) 5 return response 6 7 8 url_list = ['http://www.github.com', 'http://www.bing.com'] 9 10 for url in url_list:

利用tornado使请求实现异步非阻塞

基本IO模型 网上搜了很多关于同步异步,阻塞非阻塞的说法,理解还是不能很透彻,有必要买书看下. 参考:使用异步 I/O 大大提高应用程序的性能 怎样理解阻塞非阻塞与同步异步的区别? 同步和异步:主要关注消息通信机制(重点在B?). 同步:A调用B,B处理直到获得结果,才返回给A. 异步:A调用B,B直接返回.无需等待结果,B通过状态,通知等来通知A或回调函数来处理. 阻塞和非阻塞:主要关注程序等待(重点在A?). 阻塞:A调用B,A被挂起直到B返回结果给A,A继续执行. 非阻塞:A调用B,A不会

nodejs的异步非阻塞IO

简单表述一下:发启向系统IO操作请求,系统使用线程池IO操作,执行完放到事件队列里,node主线程轮询事件队列,读取结果与调用回调.所以说node并非真的单线程,还是使用了线程池的多线程. 上个图看看吧 举一反三:所有的异步非阻塞思路都类似,如:nginx,python的模拟异步非阻塞,还有java的nio.C#的 EAP

Nginx:异步非阻塞IO

在使用socket编程中,经常会看到阻塞.非阻塞.同步.异步,那么它们之间到底有什么关系跟区别呢? 本次将那Nginx的异步非阻塞的事件驱动模型来解释一下它们之间的关系. 阻塞IO 在linux中,默认所有socket都是阻塞的. 这意味着使用该socket调用诸如recv的函数时,在没有数据到达之前,该函数将不会返回,导致线程被阻塞,直到数据到达. 非阻塞IO 我们可以使用fcntl把socket设置为非阻塞的. 这意味着使用该socket调用诸如recv的函数时,该函数将立刻返回,可以根据返

200行自定义异步非阻塞Web框架

Python的Web框架中Tornado以异步非阻塞而闻名.本篇将使用200行代码完成一个微型异步非阻塞Web框架:Snow. 一.源码 本文基于非阻塞的Socket以及IO多路复用从而实现异步非阻塞的Web框架,其中便是众多异步非阻塞Web框架内部原理. #!/usr/bin/env python # -*- coding:utf-8 -*- import re import socket import select import time class HttpResponse(object)

node 单线程异步非阻塞

链接:http://www.runoob.com/nodejs/nodejs-callback.html 首先什么是单线程异步非阻塞? 单线程的意思整个程序从头到尾但是运用一个线程,程序是从上往下执行的.异步操作就是程序虽然是从上到下执行的,但是某个函数执行时间过长时并不会阻塞在那里等待它执行完,然后在执行下面的代码.非阻塞也就是这个意思. 为什么node是异步非阻塞的呢,得力于回调函数,还有js中的定时器也是经典的异步操作. ###4.1 Node.js异步机制 由于异步的高效性,node.j

转一贴,今天实在写累了,也看累了--【Python异步非阻塞IO多路复用Select/Poll/Epoll使用】

下面这篇,原理理解了, 再结合 这一周来的心得体会,整个框架就差不多了... http://www.haiyun.me/archives/1056.html 有许多封装好的异步非阻塞IO多路复用框架,底层在linux基于最新的epoll实现,为了更好的使用,了解其底层原理还是有必要的.下面记录下分别基于Select/Poll/Epoll的echo server实现.Python Select Server,可监控事件数量有限制: 1 2 3 4 5 6 7 8 9 10 11 12 13 14