gearman任務分發改進

基於我上次在這裏發現的問題,就是一次性投遞20個消息,用sleep等待後發現,最後一個任務需要等前面19個都跑完才能執行,所以這裏做一下改進。

client.php

<?php
$client = new GearmanClient();
$client->addServer('127.0.0.1', 4730);
for ($i=0; $i < 20; $i++) {
  $ret[$i] = $client->doBackground('runLaterJob', json_encode(array(
    'uid' => 'test user id '.$i,
    'title' => '添加一個需要延時處異步執行的代碼標題',
    'body' => '執行這個異步的具體內容',
    'run_time' => time() + 2,
  )));
}

worker.php

<?php

$worker = new GearmanWorker();
$worker->addServer('127.0.0.1', 4730);
$worker->addFunction('runLaterJob', function($job) {
  $data = json_decode($job->workload(), true);
  if (isset($data['run_time']) && $data['run_time'] > time()) {
    // 如果需要延時還沒到時間就下次再處理
    add_work($data);
  }
  else {
    echo "處理任務 uid:{$data['uid']}--title:{$data['title']}--body:{$data['body']} 成功\n";
  }
});
while($worker->work());

function add_work($data = []) {
  $client = get_client();
  $client->doBackground('runLaterJob', json_encode($data));
}

function get_client() {
  static $client = NULL;
  if (!$client) {
    $client = new GearmanClient();
    $client->addServer('127.0.0.1', 4730);
  }
  return $client;
}

核心思路是,加入任務的時候就計算好自己什麼時候執行,然後在執行任務這裏不斷的判斷是不是到時間了 到時間就執行,否則就再次加入任務,這樣就能避免最後一個任務被sleep給阻塞住了。雖然這裏一直加入任務感覺會很傻瓜,不過可以稍微做個改進,用usleep(1000)這樣每毫秒去跑一次,這樣就既能控制在毫秒級別,又能減輕循環壓力。

說幹就幹,接下來是改進的代碼。

client.php

<?php
$client = new GearmanClient();
$client->addServer('127.0.0.1', 4730);
$sleep_time = [2, 0.001, 0.005, 0.8, 0.007, 0.5, 1, 5, 0.1, 2, 2.03, 1.24, 0.12, 3.08, 4.77, 1.42, 2.69, 3.49, 0.29, 1.99];
for ($i=0; $i < 20; $i++) {
  $ret[$i] = $client->doBackground('runLaterJob', json_encode(array(
    'uid' => 'test user id '.$i,
    'title' => '添加一個需要延時處異步執行的代碼標題',
    'body' => '執行這個異步的具體內容',
    'run_time' => microtime(true) + $sleep_time[$i],
  )));
}

worker.php

<?php

$worker = new GearmanWorker();
$worker->addServer('127.0.0.1', 4730);
$worker->addFunction('runLaterJob', function($job) {
  $data = json_decode($job->workload(), true);
  if (isset($data['run_time']) && $data['run_time'] > microtime(true)) {
    // 如果需要延時還沒到時間就下次再處理
    usleep(1000);
    add_work($data);
  }
  else {
    echo "處理任務 uid:{$data['uid']}--title:{$data['title']}--body:{$data['body']} 成功\n";
  }
});
while($worker->work());

function add_work($data = []) {
  $client = get_client();
  $client->doBackground('runLaterJob', json_encode($data));
}

function get_client() {
  static $client = NULL;
  if (!$client) {
    $client = new GearmanClient();
    $client->addServer('127.0.0.1', 4730);
  }
  return $client;
}

運行php worker.php

然後新開一個終端運行php client.php

控制檯打印結果爲

處理任務 uid:test user id 1--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 2--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 4--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 8--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 12--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 18--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 5--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 3--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 6--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 11--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 15--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 19--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 0--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 9--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 10--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 16--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 13--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 17--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 14--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功
處理任務 uid:test user id 7--title:添加一個需要延時處異步執行的代碼標題--body:執行這個異步的具體內容 成功

可以看到確實是按照時間距離排序的,第0個元素排後面去了,第1個元素排最前面來了,因爲它只需要0.001秒就要執行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章