事情的背景是这样的,我想一次抓取多个网页的内容,简单的做法可以是把网址放进数组里,foreach遍历出来一个个抓取。但这样是同步的,耗时比较长,所以我想用异步多进程来实现。
我参考了workman手册http://doc.workerman.net/faq/async-task.html,写了类似的代码。
其中task worker的进程数是5,实现抓取一个网页的业务。
而主worker的进程数是1,接收到网址数组后,比如是25个网址,就建立25个AsyncTcpConnection将它们一一分发给task worker进行抓取。
代码运行的结果返回如下:
(每一行代表一个要抓取的网页,记录了执行这次抓取的task worker的id,以及抓取的用时)
(最后一行是总用时)
[attach]496[/attach]
这个结果是我希望得到的结果,25个网址,5个进程每个分别执行了5次,平均每次抓取0.25秒,总用时1.36秒也和0.25*5很接近。
但我发现类似这种25个任务平均分配给5个进程的情况很少出现。经常出现有的进程执行很多次任务,而有的只执行1次。甚至会出现25个任务全都分配给1个进程的情况,这时总用时达到了6秒 ,相当于单进程的做法?
请问使用多进程时是不是要注意什么规则?
(本人最近刚学习workman,对php的多进程也不太熟,希望各位前辈多指点)
因为workerman的网络io是异步非阻塞的,一个进程可以处理多个链接的IO事件,包括链接事件。
当瞬间给workerman发起多个异步链接时,workerman处理链接事件速度处理很快,一个进程瞬间完全可以处理多个链接事件,导致链接分配不是很均匀,操作系统为了减少进程切换开销,会尽量用当前占有cpu的进程处理这些链接事件,有的进程维持的连接数多,有的少,导致任务分配并不是百分百均匀,是正常现象。
有一些方案可以解决这个问题。
比如给Workerman添加一个pauseAccept接口和resumeAccept接口,即在task的onConnect时调用pauseAccept暂停接受新客户端链接,这样只会处理当前链接的请求,处理完后调用resumeAccept,继续接受其它链接请求。
再比如设计一个进程模型,分成两种组进程A B,A组进程只负责把异步请求收集起来,放到一个队列里面,B组进程负责在从队列里面获取,这样也能保证异步任务请求能够更快更均匀的被各个进程处理。这个可以看下 https://github.com/walkor/workerman-queue
还有一些其它的方案等待你去探索
请问 pauseAccept接口和resumeAccept接口 在哪里?
这个是很老得帖子了,现在只要workerman >= 3.5.21 并且 PHP>=7.0时 worekrman会自动平均分配连接
请问 pauseAccept接口和resumeAccept接口 在哪里? 实现了吗?有文档吗?