各路 PHP 高手,谁用过 PHP 的并发?是指 composer 里的工具包

64 天前
 abccccabc
各路 PHP 高手,谁用过 PHP 的并发?主要是 composer 里的工具包,并不是指 swoole 。

目的:用于获取 web 图片
使用场景:复制一篇经典的文章到我自己的论坛,可能含有图片 20 张左右,如果使用 curl 一张一张的取,网络不好的时候可能会超时,如果图片更多,绝对超时;如果用并发 curl 取图片,应该会很快。

希望此 composer 包能兼容的 php 版本多些。
2163 次点击
所在节点    PHP
37 条回复
lasuar
63 天前
最近发现的一条 curl 并发命令写法(8 个并发):
seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code}&'
lasuar
63 天前
seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code} &'
abccccabc
63 天前
@erquiasz0825 guzzle 简单好用,默认也是用 curl_multi_exec ,不是多线程也不是多进程,而是用非阻塞 I/O 的原理。

楼上有人建议过,我看了下,他的版本让人真的好纠结:用 v6 版本 php 版本为 >=5.5 and <8.0 ,用 v7 版本, php >= 7.2.5 。

现在在看 Yurunsoft/YurunHttp
langziyang
63 天前
ben1024
63 天前
guzzle ,reactphp 都可以,curl_multi_exec 原生也可以
zzzyyysss
63 天前
这种就该在前端用 js 处理,你的 php 只需要一个上传的接口,前端把图拿出来 然后一个个直接传给 php ,php 返回保存在服务器的地址,然后你再前端用 js 把原来的地址替换,然后保存就 ok
liaoxx
63 天前
有幸写过一个用 yeild 和 guzzle/http 的请求池写过一个工具类
/**
* 异步/并发/批量请求 (慎用)
* @param string $url 请求地址
* @param array $allParams 所有请求参数 int[{once request params}]
* @param array $options 请求配置 ['headers'=>[]]
* @param callable|null $onSuccess 请求成功回调函数 function(ResponseInterface $response,int $index,array $params){}
* @param callable|null $onFailure 请求失败回调函数 function(\Exception $exception,int $index,array $params){}
* @param callable|null $onComplete 请求完成回调函数
* @return void
* @author LiaoYongjian
* @date 2024-01-19 17:43
*/
public function postAsyncRequests(string $url, array $allParams, array $options = [], callable $onSuccess = null, callable $onFailure = null, callable $onComplete = null)
{
$headers = $options['headers'] ?? [];
$client = $this->getCli();

//生成器 用于生成异步请求
$generator = function () use ($client, $allParams, $url, $headers, $onSuccess, $onFailure) {
foreach ($allParams as $index => $params) {
yield function () use ($client, $url, $headers, $index, $params, $onSuccess, $onFailure) {
//异步请求
return $client->postAsync($url, [
'headers' => $headers,
'json' => $params,
])->then(
function ($response) use ($onSuccess, $index, $params) {
if ($onSuccess) {
$onSuccess($response, $index, $params);
}
return $response;
},
function (\Exception $e) use ($onFailure, $index, $params) {
if ($onFailure) {
$onFailure($e, $index, $params);
}
throw $e;
}
);
};
}
};
//异步请求池
$pool = new Pool($client, $generator());
//异步请求池的回调函数
$responses = $pool->promise()->wait();
if ($onComplete){
$onComplete($responses);
}
}
cybort
63 天前
超时是给你限流了吧,你请求的快限的更快。
putyy
63 天前
原生 curl_multi
putyy
63 天前
如果资源存的七牛 还可以用七牛云的接口帮下载
abccccabc
62 天前
@zzzyyysss

你说的是这样的吗?
```
var allimg = 获取到的图片数组;
var oldcontent = 原内容;
for(var i=0; i<allimg.length; i++){
$.post('url', 参数, function(ret) {
if(ret['code'] == 200) {
oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl']);
}else{
console.log(错误信息);
}
}, 'json');
}
```

这样有一个很大的问题:多个异步去修改同一全局变量,必须要锁定全局变量 oldcontent ,然后用队列的形式去替换 oldcontent 内容,不然最后只会有一个修改 oldcontent 生效。

这样更麻烦,搞不定。

-------------------
php 用了并发,现在问题也不小,
```
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>AccessDenied</Code>
<Message>You are denied by bucket referer policy.</Message>
<RequestId>65F44FE6D4BE2035341DF46B</RequestId>
<HostId>40114.oss-cn-beijing.aliyuncs.com</HostId>
<BucketName>blog-picture-240114</BucketName>
<EC>0003-00000503</EC>
<RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000503</RecommendDoc>
</Error>
```
这节奏似乎只能放弃 PHP 并发了。
abccccabc
62 天前
@putyy 用不起云存储,个人小论坛,用来记录我的学习而已。

@cybort 确实是并发超过一定数量后,部分主机会限制。直接返回类似 403 这种
zzzyyysss
62 天前
你为什么要锁定全局变量,你的目标不就是 源代码中的 图片地址远程换本地吗?
你可以在任何时间点 处理这个操作。
js 那个方法 你只要在上传完毕之后,用最新的地址 从富文本中替换旧地址就可以了。
或者你在点击保存按钮之后加个 loading 统一处理。
之所以推荐你在前端处理是因为有些网站你用后台 php 去抓图片会有防盗链的。
abccccabc
62 天前
@zzzyyysss 我试过了,多个异步去修改 oldcontent 替换旧图片地址,只有 for 循环最后 i 变量替换操作生效。 现在我明白,是要对 oldcontent 加锁,这应该就是竞争。太深澳了,又搞不定。唉。


看来现在得请教 JS 高手了。
zzzyyysss
62 天前
```
const images = [];
const replaceData = {};
const asyncPost = (url, data) => {
return new Promise((resolve, reject) => {
$.post(url, data, (ret) => {
if(ret['code'] == 200) {
resolve(ret);
} else {
reject('获取图片出错')
}
})
})
}
// 每当拿到新的图片时调用
const onNewImage = async (oldImgUrl) => {
if (!replaceData[oldImgUrl]) {
const ret = await asyncPost(url, data);
replectData[ret['oldImgUrl']] = ret['newImgUrl'];
}
}
// 在保存之前 处理 content
const beforeSubmit = (content) => {
Object.keys.forEach(oldUrl => {
content.replaceAll(oldUrl, replaceData[newUrl])
})
return content;
}
```
大概就是这样,你可以试试
alex8
48 天前
没有稳定的原生解决方案, 上层的 composer 里更不会有。
lyxxxh2
31 天前
guzzlephp 就有啊,文档都写着...
官方 curl 也有,更麻烦。

https://docs.guzzlephp.org/en/stable/quickstart.html

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

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

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

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

© 2021 V2EX