Gevent 是怎么在单线程中实现并发的呢?
教程链接: http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/001407503089986d175822da68d4d6685fbe849a0e0ca35000
廖雪峰大大的教程中,有这么一句
3 个网络操作是并发执行的,而且结束顺序不同,但只有一个线程
我不理解,为什么单线程就能够并发 3 个网络请求呢
----------------------- 以下是精选回复-----------------------
答:不是说了协程了么……
答:异步吧,我也不了解
答:你这问题就像单核 cpu 怎么支持多任务一样
需要调度器
答:因为 io 是异步的
答:这个问题问题很好。虽然我没有自己实现过,但我理解大概是这样的。
要理解两个概念: 1. 协程( coroutine ) 2.事件驱动( event-driven )。
1. coroutine (类似于 python 里面的 yield 语法),是把一个 function 执行过程暂停,将其 stack 状态保存,当你需要的时候恢复 stack 状态,从暂停的地方继续执行。
通过这样,你可以自由的控制程序的暂停和恢复。在你的例子里面其实是,把每个 function 执行到 io 操作时都暂停,等你需要的时候( io 返回结果的时候)恢复执行。
但问题是,什么时候你知道 io 返回结果了呢?就需要另外一个机制通知你。
2. event-driven 就是通知你 io 操作完成的机制。基本想法就是 io 操作发生时,你把 io 的 file descriptor 存到一个 poll 里面,操作系统会监控这个 poll 。当其中有 io 结束的时候,操作系统会给你的程序发一个 signal ( event ),告诉你哪一个 io 结束了。这样你就知道什么时候恢复你的程序执行了。
当然这么简单说一说,如果不了解操作系统底层的一些知识,感觉还是挺难理解的。
我猜是这么回事,有不对的请指出。
答:线程有三个状态:等待 wait ,就绪 ready 和运行 running 。
答:很多方案,例如:完成端口
答:推荐先看下这两篇文章,作为入门知识
https://mp.weixin.qq.com/s?__biz=MzA4MjEyNTA5Mw==&mid=2652563599&idx=1&sn=9781747e54d906c0c140228376e671ed&scene=0&key=a85c0ff7a76aa0683b2f70c70c0be3e5247dc1bb8d68bcceda77fa55d21a376780751af24b70ecea18a839ed8844e1ed692694a7a613c21a4e16e3d452476980c0786681dc1004808b58292ebe2cc13b&ascene=0&uin=Njc4OTQwMzgw&devicetype=iMac+MacBookPro12%2C1+OSX+OSX+10.12.2+build(16C67)&version=12010310&nettype=WIFI&fontScale=100&pass_ticket=GTEUg%2BGkeOGSFphViBMWCMwafaGhAsNDL6pnzjYRggXhFYTCg481M%2BgM0pRneMxV
https://mp.weixin.qq.com/s?__biz=MzA4MjEyNTA5Mw==&mid=2652563602&idx=1&sn=7d3f4b20a04d875ae62c64ceaf6f6c36&scene=0&key=a85c0ff7a76aa0681083a51fcd65e35b636952ad59cb87bcf1fb2b47b529b3ffc6141578240fff53e38d93f1c438b05e3111e0855ae884ceccf0e0ad08f5c608fdc42548872c9953eeb3f2e9b8007e5e&ascene=0&uin=Njc4OTQwMzgw&devicetype=iMac+MacBookPro12%2C1+OSX+OSX+10.12.2+build(16C67)&version=12010310&nettype=WIFI&fontScale=100&pass_ticket=GTEUg%2BGkeOGSFphViBMWCMwafaGhAsNDL6pnzjYRggXhFYTCg481M%2BgM0pRneMxV
答:13 楼第二个链接贴错了,先看这个[聊聊同步、异步、阻塞与非阻塞]
http://mp.weixin.qq.com/s?__biz=MzA4MjEyNTA5Mw==&mid=2652563596&idx=1&sn=ea234e176e36775effa9634f105ecf6d&scene=21#wechat_redirect
答:只有一个 cpu ,多线程 /多进程是怎么做到并发执行的呢?
开个玩笑……
在多线程的思路中,每个线程处理一个连接,连接没有数据的时候,就阻塞等待,有数据的线程运行。
在异步的思路中,一个线程同时等待多个连接的数据,哪个连接先来了数据就先处理哪个连接,处理完马上回到阻塞状态。
系统调用 poll 、 select 、 epoll ( linux ) 等提供一个线程可以同时等待多个连接的机制。
因为网络编程中,等待网络数据是耗时最多的状态,所以使用异步的方法效率很高。
答:时间片
答:稍微看了下 gevent 的具体实现。基本思路是把 python 标准库里面的所有 io 操作都变成 event driven 。好大的工程。。。
首先是 monkey.patch_all 实际是把所有的 io 模块都打了补丁,具体可以看 patch_module 那个函数,用 gevent.{os, socket, sys...}自定义的操作替代了原生标准模块的操作。
https://github.com/gevent/gevent/blob/master/src/gevent/monkey.py#L583
https://github.com/gevent/gevent/blob/master/src/gevent/monkey.py#L152
比如 gevent.socket 这个模块其实是覆盖了原生的 socket 模块,关键操作在 socket._wait 这个函数,把 io event 注册到 gevent.hub 里面。
https://github.com/gevent/gevent/blob/master/src/gevent/_socket3.py#L306
https://github.com/gevent/gevent/blob/master/src/gevent/_socket3.py#L157
gevent.hub 是对 eventloop 的实现。
https://github.com/gevent/gevent/blob/master/src/gevent/hub.py
答:我刚开始也有这个困惑
https://pymotw.com/2/select/
答:cpu 计算协程无效。跑满 100%就只能干瞪眼了。
协程完成 io 调度后, cpu 还可以干别的。(让学霸同学帮你写作业,你自己可以去打 dota 这种需要 cpu 的劳动,学霸同学写完作业向你报告,你给他 100 块让他滚蛋,顺便打电话喊女朋友送饭给你吃)
答:那不知道楼主是否知道并发的意思呢,如果明白楼上的各位回答很清楚了。。
答:来看看这个 https://www.zhihu.com/question/20703476/answer/15911452
答:如果没有任务阻塞,那么在单处理器上使用并发就没有任何意义。有阻塞的话,就是切分 CPU 时间片, cpu 轮流给每个任务分配占用时间。
答:我觉得楼主你需要了解是 gevent 后面的这两个: https://www.google.com.hk/webhp?sourceid=chrome-instant&ion=1&espv=2&ie=UTF-8#newwindow=1&safe=active&q=libevent+kqueue
答:非阻塞就可以实现单个线程并发了。
软件的线程本身就是非阻塞的,所以一个 CPU 线程可以运行几百几千个软件线程。
同理如果你操作也是非阻塞的,那一个软件线程也就可以运行几百几千个操作了。
0条评论