V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  sxbxjhwm  ›  全部回复第 1 页 / 共 6 页
回复总数  106
1  2  3  4  5  6  
@MSIAM 可能是非标端口的 TLS 通讯?
@learningman IDC,服务器上架
弱智老板又提了一个不切实际的需求,屁都不懂的产品经理还在那一本正经分析怎么做的时候 —— 不开心
(我司老板新需求:机房配好以后可以实现系统自动扫描网络,把全部服务器添加进系统里

老板没来催进度没提新需求,和同事一起骂老板 —— 开心
@jfdnet 美亚买的希捷中国能保么,西数已经明确不能转保了
194 天前
回复了 aptupdate 创建的主题 宽带症候群 上海地区有没有便宜的宽带推荐
http://www.189.cn/sh/support/tariff/package/114340.html 100/20,39 一个月,100 安装费算上 568 首年 468 续费,未发现需要缴纳押金,可能需要去直营营业厅(比如西区的江苏路营业厅)办理
https://emall.sh.189.cn/shop/html/30010004/100612.html 100/20,360 一年,200 安装费算上 560 首年 360 续费,押金 200,是从原 20/4 的天天宽带 http://www.189.cn/sh/support/tariff/package/109892.html 升级而来的
https://kdslife.com/t_10584935_0_5.html 宽带山这个贴也可参考
209 天前
回复了 pytth 创建的主题 PHP PHP 查询符合条件的数组问题
@sun2920989 我的例子并没有用到多个 curl_multi_init 的实例,curl_multi_init 返回的是一个栈,你就把它当成一个队列,所有 curl_multi_exec 都在复用这个栈,如果你有需求大可以多创建几个队列,但这样显然没有意义。
@sun2920989 我其实有一点不理解,既然是同步的 fpm,为什么不等到获取数据后统一再处理呢,效率上没差的
@sun2920989 之前做过一个 cli 的爬虫,当时是用 swoole 解决的。做法就是专门起一个负责 task 的进程,用 \Swoole\Server 监听一个 sock 文件,具体文档 https://wiki.swoole.com/#/consts?id=socket-%e7%b1%bb%e5%9e%8b 。做的时候有些偷懒没有用 redis,而是直接用 \Swoole\Table 做基础的共享数据存储,sock 负责队列控制。虽然用 swoole 实现在语法上很好看,用起来却比 curl_multi_exec 要麻烦得多,后续再也没有用过这个方案,在这边讨论这个方案稍微有点超纲,算是之前踩过的坑提醒一下,附一个当时写的部分源码:

```php
protected function execute(Input $input, Output $output)
{
/**
* $initDataTable 基础配置表,用于实例化爬虫类
* |------------------------------------|
* | key | value |
* |------------------------------------|
* | service | service |
* | baseUrl | https:// |
* | cookieJar | json_encode(cookieJar) |
* |------------------------------------|
*/
$initDataTable = new \Swoole\Table(4);
$initDataTable->column('value', \Swoole\Table::TYPE_STRING, 512);
$initDataTable->create();

/**
* $acquiredListTable 记录已由 getList 方法执行过的操作
* |------------------------------|
* | key | value |
* |------------------------------|
* | getDatacenters | 0 |
* | getIpsGroupList | 0 |
* | getIpsList | 0 |
* | getSwitchList | 0 |
* | getHardwareModelList | 0 |
* | getPurchaseList | 0 |
* | getServerList | 0 |
* | getHardwareList | 0 |
* |------------------------------|
*/
$acquiredListTable = new \Swoole\Table(16);
$acquiredListTable->column('count', \Swoole\Table::TYPE_INT, 1);
$acquiredListTable->create();

$workingAtomic = new \Swoole\Atomic();
$successedAtomic = new \Swoole\Atomic();
$failedAtomic = new \Swoole\Atomic();

$serv = new \Swoole\Server(Env::get('runtime_path') . 'task.sock', 0, SWOOLE_PROCESS, SWOOLE_SOCK_UNIX_STREAM);
$serv->table = ['initData' => $initDataTable, 'acquiredList' => $acquiredListTable];
$serv->atomic = ['working' => $workingAtomic, 'successed' => $successedAtomic, 'failed' => $failedAtomic];

$serv->set(array('task_worker_num' => 15));

$serv->on('receive', function($serv, $fd, $from_id, $data) use ($output) {
$this->receive($serv, $fd, $from_id, $data, $output);
});

$serv->on('task', function ($serv, $task_id, $from_id, $data) use ($output) {
$this->task($serv, $task_id, $from_id, $data, $output);
});

$serv->on('finish', function ($serv, $task_id, $data) use ($output) {
$this->finish($serv, $task_id, $data, $output);
});

$serv->start();
}
```
@sun2920989 阿我原先还以为你做的是一个采集爬虫,没想到是 fpm 。。curl_multi_exec 这东西其实本身是异步的,只不过你需要在同步的 php 里调用只能在适当的地方写阻塞,其实不光是 curl,其他类似的队列要实现并发控制也得用阻塞的方法来控制,php 不像 node 一类的语言,可以通过触发事件来实现完全的异步,这个是最大的问题
@sun2920989 如果是我处理这样的需求,可能会选择直接用 cli 起个 daemon 进程,用 redis 负责队列,cli 自己从 redis 取任务 + 控制并发,这样通用性更强一些
@sun2920989 curl_multi_exec 输出之前都可以抽出来作为 push 方法的内容,sleep 那部分是假装你执行自己需要的功能,sleep 之后是真正的 exec
@sun2920989

我这边比较偷懒是直接在原来 Multi 类的基础上修改的,而且因为我原先的设计返回数据的 key 需要与传入的 key 对应,用了 next 直接操作数组内部指针,生怕追加任务指针会被 reset,所以就没有给 class 再加 push 方法,理论上后续再加,再次执行 exec 都是没问题的。我这边输出的结果很明显的展示了在执行 curl_multi_exec 后进行任意操作都不会影响已发出的请求,传入 callback 也可以预处理每一个返回值,至于并发控制这块,因为需要达到精准控制数量所以只能写在 while 段里所以不能很好的避免阻塞:

[email protected]:~/php-curl-class# php test.php
Start: 1620584188.6943
curl_multi_exec: 1620584188.6959
sleep: 1620584191.6963
test1 received data at: 1620584193.697
test3 received data at: 1620584193.6971
test4 received data at: 1620584193.6979
test2 received data at: 1620584193.6989
test5 received data at: 1620584198.6994
test6 received data at: 1620584198.6994
test7 received data at: 1620584198.7006
test8 received data at: 1620584198.7009
array(8) {
["test1"]=>
string(40) "strlen: 259 data: float(1620584193.6961)"
["test3"]=>
string(40) "strlen: 259 data: float(1620584193.6966)"
["test4"]=>
string(40) "strlen: 259 data: float(1620584193.6969)"
["test2"]=>
string(40) "strlen: 259 data: float(1620584193.6965)"
["test5"]=>
string(40) "strlen: 259 data: float(1620584198.6985)"
["test6"]=>
string(39) "strlen: 258 data: float(1620584198.699)"
["test7"]=>
string(40) "strlen: 259 data: float(1620584198.6994)"
["test8"]=>
string(37) "strlen: 256 data: float(1620584198.7)"
}
Done: 1620584198.7015
@sun2920989 等周一吧,我发个 gist
@sun2920989 curl_multi_exec 本来就是 while 在一直调用的,它只是启动这个栈中所有的 curl 句柄而已 https://www.php.net/manual/zh/function.curl-multi-exec.php ,限制并发相关的源码在我之前贴的 GitHub 链接里其实都有,如果你实际测试一下就会发现它也能很好做到并发控制与重试的。
@sun2920989 你没看我封装的源码。。我实现了请求错误时的重试机制,原理就是在 exec 后继续使用 curl_multi_add_handle 向栈里推句柄实现的
@sun2920989 你是希望预处理数据返回阿,那 curl_multi_info_read 和 curl_multi_getcontent 完全可以满足你的需求的,具体可以看这一段 https://github.com/jshensh/php-curl-class/blob/master/src/Multi.php#L118-L129 。我在这里就是将原有的 curl 句柄进行处理后放在待返回的数组里最后统一扔出来的。如果需要更细致的并发我可能就是采用 pcntl_ 系列方法处理了
@sun2920989 curl_multi_exec 通过第二个引用传参 &$still_running 来告诉你栈中还有多少正在执行的 curl 句柄。阻塞的是后续获取的那部分 while 段源码,它通过判断 $still_running 来确认有没有全部执行完,同时在 while 循环体内也有通过 curl_multi_exec 对 $still_running 重新赋值的操作,所以在什么阻塞获取是完全可以由你自己决定的。
1  2  3  4  5  6  
关于   ·   帮助文档   ·   API   ·   FAQ   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2391 人在线   最高记录 5497   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 31ms · UTC 15:25 · PVG 23:25 · LAX 07:25 · JFK 10:25
♥ Do have faith in what you're doing.