GearmanClient::addTaskBackground

(PECL gearman >= 0.5.0)

GearmanClient::addTaskBackground添加一个要在后台并行运行的任务

描述

public GearmanClient::addTaskBackground(
    string $function_name,
    string|int|float $workload,
    mixed $context = null,
    ?string $unique_key = null
): GearmanTask|false

添加一个要在后台并行运行的任务,与其他任务并行运行。对要并行运行的所有任务调用此方法,然后调用 GearmanClient::runTasks() 执行工作。

参数

function_name

工作进程要执行的已注册函数

workload

要处理的序列化数据

context

与任务关联的应用程序上下文

unique_key

用于识别特定任务的唯一 ID

返回值

一个 GearmanTask 对象或 false 如果无法添加任务。

示例

示例 #1 两个任务,一个后台任务,一个非后台任务

此示例说明了在后台运行任务和正常任务之间的区别。客户端添加两个任务来执行相同的函数,但其中一个使用 addTaskBackground() 添加。设置了一个回调,以便可以跟踪作业的进度。一个带有模拟延迟的简单工作进程报告作业进度,客户端通过回调获取这些信息。两个工作进程用于此示例。注意,后台任务不会显示在客户端输出中。

<?php

# 客户端脚本

# 创建我们的 Gearman 客户端
$gmc= new GearmanClient();

# 添加默认的作业服务器
$gmc->addServer();

# 设置几个回调,以便我们能够跟踪进度
$gmc->setCompleteCallback("reverse_complete");
$gmc->setStatusCallback("reverse_status");

# 为 "reverse" 函数添加一个任务
$task= $gmc->addTask("reverse", "Hello World!", null, "1");

# 添加另一个任务,但这个任务要在后台运行
$task= $gmc->addTaskBackground("reverse", "!dlroW olleH", null, "2");

if (!
$gmc->runTasks())
{
echo
"ERROR " . $gmc->error() . "\n";
exit;
}

echo
"DONE\n";

function
reverse_status($task)
{
echo
"STATUS: " . $task->unique() . ", " . $task->jobHandle() . " - " . $task->taskNumerator() .
"/" . $task->taskDenominator() . "\n";
}

function
reverse_complete($task)
{
echo
"COMPLETE: " . $task->unique() . ", " . $task->data() . "\n";
}

?>
<?php

# 工作脚本

echo "启动中...\n";

# 创建 worker 对象。
$gmworker= new GearmanWorker();

# 添加默认服务器 (localhost)。
$gmworker->addServer();

# 向服务器注册函数 "reverse"。
$gmworker->addFunction("reverse", "reverse_fn");

print
"等待任务...\n";
while(
$gmworker->work())
{
if (
$gmworker->returnCode() != GEARMAN_SUCCESS)
{
echo
"返回码: " . $gmworker->returnCode() . "\n";
break;
}
}

function
reverse_fn($job)
{
echo
"接收任务: " . $job->handle() . "\n";

$workload = $job->workload();
$workload_size = $job->workloadSize();

echo
"工作负载: $workload ($workload_size)\n";

# 此状态循环并非必需,仅用于演示其工作原理
for ($x= 0; $x < $workload_size; $x++)
{
echo
"发送状态: " . ($x + 1) . "/$workload_size 完成\n";
$job->sendStatus($x+1, $workload_size);
$job->sendData(substr($workload, $x, 1));
sleep(1);
}

$result= strrev($workload);
echo
"结果: $result\n";

# 返回要发送回客户端的内容。
return $result;
}

?>

两个 worker 运行时的 worker 输出

Received job: H:foo.local:65
Workload: !dlroW olleH (12)
1/12 complete
Received job: H:foo.local:66
Workload: Hello World! (12)
Sending status: 1/12 complete
Sending status: 2/12 complete
Sending status: 2/12 complete
Sending status: 3/12 complete
Sending status: 3/12 complete
Sending status: 4/12 complete
Sending status: 4/12 complete
Sending status: 5/12 complete
Sending status: 5/12 complete
Sending status: 6/12 complete
Sending status: 6/12 complete
Sending status: 7/12 complete
Sending status: 7/12 complete
Sending status: 8/12 complete
Sending status: 8/12 complete
Sending status: 9/12 complete
Sending status: 9/12 complete
Sending status: 10/12 complete
Sending status: 10/12 complete
Sending status: 11/12 complete
Sending status: 11/12 complete
Sending status: 12/12 complete
Sending status: 12/12 complete
Result: !dlroW olleH
Result: Hello World!

客户端输出

STATUS: 1, H:foo.local:66 - 1/12
STATUS: 1, H:foo.local:66 - 2/12
STATUS: 1, H:foo.local:66 - 3/12
STATUS: 1, H:foo.local:66 - 4/12
STATUS: 1, H:foo.local:66 - 5/12
STATUS: 1, H:foo.local:66 - 6/12
STATUS: 1, H:foo.local:66 - 7/12
STATUS: 1, H:foo.local:66 - 8/12
STATUS: 1, H:foo.local:66 - 9/12
STATUS: 1, H:foo.local:66 - 10/12
STATUS: 1, H:foo.local:66 - 11/12
STATUS: 1, H:foo.local:66 - 12/12
COMPLETE: 1, !dlroW olleH
DONE

参见

添加注释

用户贡献注释 3 注释

匿名
8 年前
此示例可能无法按预期工作。

前台作业会阻塞,但后台作业不应该。(如果阻塞,那不是我所知的已记录的 Gearman 行为,并且对后台作业来说也不合理)。

因此,如果前台作业完成,我们期望 runTasks() 在那时返回,无论后台作业(s)的状态如何。在此示例中,没有其他工作要做,php 脚本(客户端)将在那时退出。

要充分利用后台作业,我们合理地假设我们仍然希望知道它们的状态。为此,您需要一个轮询循环,它“检查它们”并等待它们完成。

当然,这消除了后台作业的意义 - 因为客户端仍然会阻塞(在轮询循环中),或多或少地被占用,并且无法退出/完成。

因此,在实践中,后台作业意味着您在执行后与客户端分离(因为主要目的是释放客户端,否则只使用前台执行),这意味着客户端可能会退出,这意味着作业本身应该独立报告其状态和最终结果,而不是留给客户端。

与前台作业相比,这是一个完全不同的设置。事实上,这个例子甚至混合这两个东西有点愚蠢。

没有人会看到这篇文章,因为显然世界上没有人对 php gearman 客户端发表过评论,但这仍然是一篇好文章。
iunknowvb at gmail dot com
6 年前
function run_process($cmd,$outputFile = '/dev/null', $append = false){
$pid=0;
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd = 'wmic process call create "'.$cmd.'" | find "ProcessId"';
$handle = popen("start /B ". $cmd, "r");
$read = fread($handle, 200); //Read the output
$pid=substr($read,strpos($read,'=')+1);
$pid=substr($pid,0,strpos($pid,';') );
$pid = (int)$pid;
pclose($handle); //Close
}else{
$pid = (int)shell_exec(sprintf('%s %s %s 2>&1 & echo $!', $cmd, ($append) ? '>>' : '>', $outputFile));
}
return $pid;
}
function is_process_running($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
//tasklist /FI "PID eq 6480"
$result = shell_exec('tasklist /FI "PID eq '.$pid.'"' );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('ps %d 2>&1', $pid));
if (count(preg_split("/\n/", $result)) > 2 && !preg_match('/ERROR: Process ID out of range/', $result)) {
return true;
}
}
return false;
}
function stop_process($pid){
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$result = shell_exec('taskkill /PID '.$pid );
if (count(preg_split("/\n/", $result)) > 0 && !preg_match('/No tasks/', $result)) {
return true;
}
}else{
$result = shell_exec(sprintf('kill %d 2>&1', $pid));
if (!preg_match('/No such process/', $result)) {
return true;
}
}
}
$cmd='';
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {//'This is a server using Windows!';
$cmd= $php_path.'\php.exe '.$path.'\long_process.php' ;
}else{
$cmd='/usr/bin/php -f /var/www/example.com/public/long_process.php';
}

$pid=run_process($cmd);
raitech at gmail dot com
8 年前
这种方法似乎只在您不需要了解有关 worker 的任何信息时有用,当您可以让 runTasks() 完成其代码并销毁 GearmanClient 对象而不会出现问题时。

如果您需要通过回调从 worker 获取数据,那么在 runTasks() 完成后就忘记它吧。

您必须在 GearmanClient 的“主循环”中阻塞您的执行,以便它可以调用回调。似乎 runTasks() 就是这个“主循环”。
To Top