io 复用就是一个线程可以监听多个连接,减少无谓的切换,但是在监听到改变之后,依然可能被阻塞住啊?

2016-07-31 17:03:16 +08:00
 petelin

比如 100 个客户端,连接到了服务器,然后都停止操作, epoll 好处就是一个进程(线程)就可以 hold 住 100 个连接,而不用创建 100 个进程或线程由操作体统来切换上下文,给每个线程都分一点时间,而是当有客户端传送过来数据的时候,阻塞结束可以进行下一步操作,伪代码:

for loop 
	# 阻塞等待 100 个客户端返回一个可读的 socket
    
    # def dosomething

问题是如果在 do something 里进行数据库连接等费时间的 io 操作,响应时间依然感人啊。。。

比如两个人并发访问,第一个人 do something,花了三秒(io 操作),下一个用户就得等三秒才开始为他服务,,,,

我的理解是否有错误?解决do something里面 io 时间的又是什么技术?我大概觉得能用 gevent ( io 阻塞的时候 yield 到其他协程),但是想不明白具体是怎么做的,有什么文章或者书吗?谢谢大家。

1949 次点击
所在节点    问与答
9 条回复
SErHo
2016-07-31 17:15:23 +08:00
"进行数据库连接等费时间的 io 操作" 也就是说你在“异步”(姑且叫异步吧,其实是事件循环)里面进行了耗时的同步 IO 操作,这是错误的。。。

解决方法就是把这个数据库同步 IO 操作改成异步的,加入到你主体的事件循环里面,问题是很麻烦做到,有时候不可能,想想在 tornado 里面做数据操作的时候,这就是为什么有那么多针对 tornado 数据库操作的库,如 https://github.com/PyMySQL/Tornado-MySQL

所以需要 gevent 或者 golang 这种在框架或语言底层自动将 IO “异步”化(多路复用)的技术。
petelin
2016-07-31 17:29:57 +08:00
@SErHo 确实是`事件循环`,那就是说我对这种服务器框架的理解还是对的,单个线程就是通过死循环一个一个的处理请求。
在时间循环里进行异步 io ,,,(⊙o⊙)…我小小的脑子想不出来改怎么调度啊,,,先处理 触发的事件呢,还是先处理 回调的事件呢,他怎么知道回调的函数改执行了,这都是在一个线程里啊
SErHo
2016-07-31 17:52:43 +08:00
@petelin 所以说做到很麻烦啊,要进行详尽的规划和拆分,你看看 Nginx 的 upstream 相关的模块那代码写的是多蛋疼,回调过去回调过来的,这就是为啥业务复杂了还是用协程(gevent, golang) 这类的爽。
akira
2016-07-31 18:04:25 +08:00
理解没问题,所以 dosomething 里面尽量不要有耗时的操作
oska874
2016-07-31 18:55:10 +08:00
dosomething 里再启个线程?
julyclyde
2016-07-31 23:11:30 +08:00
socket 可以是 NONBLOCKING 的啊
为什么你认为必须阻塞?
shyling
2016-08-01 01:15:48 +08:00
@SErHo golang 神马时候变成协程了
IwfWcf
2016-08-01 02:48:08 +08:00
协程大法好
petelin
2016-08-01 08:33:21 +08:00
@julyclyde 我按 epoll 那个模型说的,但是他阻不阻塞跟你写的 view 函数阻不阻塞没关系。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/296158

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX