[英]How can a function be run multiple times at the same time in php?
我有一个用 cron 运行的页面。 此页面上的函数向链接发送请求,该请求返回的示例 json 如下所示。
First Request
{
"next": "randomToken123",
"previous": null,
"items": [
{
....
},
{
....
}
]
}
Second Request
{
"next": "randomToken456",
"previous": null,
"items": [
{
....
},
{
....
}
]
}
我在这里要做的主要事情是能够发送另一个请求,而无需等待在前一个请求之后采取的操作,方法是在第一个请求之后返回下一个值。 因此,让我通过一个函数示例向您展示:
public function cronFunc($next_cursor = null) {
$result = doRequest($next_cursor);
updateTheDatabaseTable($result);
}
我想通过同时运行上述函数3次同时将返回的项目添加或更新到数据库中。 所以,我想同时执行 3 个事务。 是否可以用线程来做到这一点? 还是有其他方法? 我尝试使用 header('Location:...') 函数来执行此操作,但过了一会儿它给出了一个错误,说 too_many_redirects。
将有大约 100 万+个数据,每个请求将进行 200 次更新。 因此,由于我想在这里运行 3 次,我将一次进行 600 次更新。
我提供了两种解决方案来解决这个问题。 一种是使用多线程,一种是使用 cronjobs。
PHP中有一些支持多线程的库。
alfallouji/php_multithread
您可以使用以下命令安装此多线程库:
composer require alfallouji/php_multithread
这取决于带有以下软件包的 PCNTL:
sudo apt-get install php-cli
alfallouji/php_multithread
此代码是对上述概念的模拟。 将以下代码添加到 test.php,然后运行php test.php
:
<?php
require_once __DIR__ . "/vendor/autoload.php";
$manager = new Threading\Multiple(100);
class Task extends \Threading\Task\Base
{
private $params = [], $manager;
public function __construct(array $params, \Threading\Multiple $manager)
{
$this->params = $params;
$this->manager = $manager;
}
public function initialize()
{
return true;
}
public function onSuccess()
{
return true;
}
public function onFailure()
{
return false;
}
# For demo; get next token; or false
private function getToken()
{
return array_rand([rand(1000, 99999)=>0,rand(1000, 99999)=>0,rand(1000, 99999)=>0,-1=>-1]);
}
public function process(array $params = array())
{
echo getmypid() . "(token: ".$this->params['token'] . ") - init" . PHP_EOL;
sleep(1); # fake some heavy process
if(!isset($this->params['token'])) {
echo getmypid() . "(token: ".$this->params['token'] . ") - Do first request here " . PHP_EOL;
$this->manager->start(new Task(['token'=>'randomTokenFirst'], $this->manager));
} elseif(isset($this->params['token']) && $this->params['token'] !== -1) {
$token = $this->getToken();
echo getmypid() . "(token: ".$this->params['token'] . ") - New token obtained (".$token.") " . PHP_EOL;
$this->manager->start(new Task(['token'=>$token], $this->manager));
} else {
echo getmypid() . "(token: ".$this->params['token'] . ") - Last request done " . PHP_EOL;
}
sleep(1); # fake some heavy process
//Handle request here
echo getmypid() . "(token: ".$this->params['token'] . ") - Processing " . PHP_EOL;
return true;
}
}
$manager->start(new Task(['token'=>0], $manager));
输出将是一些调试信息。 它实际上将从第一个请求(没有令牌)运行到结束:
280004(token: 0) - init
280004(token: 0) - New token obtained (64865)
280005(token: 64865) - init
280004(token: 0) - Processing
280005(token: 64865) - New token obtained (68564)
280006(token: 68564) - init
280005(token: 64865) - Processing
280006(token: 68564) - New token obtained (54573)
280007(token: 54573) - init
280006(token: 68564) - Processing
280007(token: 54573) - New token obtained (63093)
280008(token: 63093) - init
280007(token: 54573) - Processing
280008(token: 63093) - New token obtained (89230)
280010(token: 89230) - init
280008(token: 63093) - Processing
280010(token: 89230) - New token obtained (82375)
280011(token: 82375) - init
280010(token: 89230) - Processing
280011(token: 82375) - New token obtained (-1)
280012(token: -1) - init
280011(token: 82375) - Processing
280012(token: -1) - Last request done
280012(token: -1) - Processing
我将解释一个简单的概念,应该根据您自己的需要进一步调整。 PHP 官方不包含多线程,因此大多数情况下这些解决方案是使用 cronjobs 实现的。
您可以设置一个数据库表来跟踪请求中的最后一个令牌。 或者,例如,您可以将令牌存储在 json 中。 这将为脚本的下一次执行提供信息。
您可以每五秒运行一次 cronjob 并从数据库或 json 中读取令牌值:
* * * * * ( php script.php )
* * * * * ( sleep 5 ; php script.php )
* * * * * ( sleep 10 ; php script.php )
* * * * * ( sleep 15 ; php script.php )
* * * * * ( sleep 20 ; php script.php )
* * * * * ( sleep 25 ; php script.php )
* * * * * ( sleep 30 ; php script.php )
* * * * * ( sleep 35 ; php script.php )
* * * * * ( sleep 40 ; php script.php )
* * * * * ( sleep 45 ; php script.php )
* * * * * ( sleep 50 ; php script.php )
* * * * * ( sleep 55 ; php script.php )
您可以通过在数据库中实现计数器或布尔值以及令牌值来防止 cronjob 执行相同的令牌两次。 并且您应该提供一些逻辑来知道何时到达终点(下一个请求不再返回令牌)。
如果您想限制同时发出的请求数,我的建议是切换到 Java。 PHP 本身并不支持多线程,因此缺少很多 Java 中包含的特性。 例如,Java Semaphore 对象可以根据许可数量限制同时对特定资源完成的请求数量。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.