snidel

其他类别 2025-07-29

snidel

一个多进程容器。 snidel使所有PHP开发人员更容易在没有任何扩展的情况下进行并行处理。

请考虑向该项目的作者Akihito Nakano捐款,以表达您的❤️和支持。

赞助商@ackintosh在Github赞助商上

snidel解决了什么?

(en)

没有几个人,使用PHP开始他们的编程运营商,然后继续。并行处理,他们不熟悉它,可能是他们的障碍。

否则,那些不得不使用PHP的语言开发的人(例如一种具有较高功能的语言用于并行处理)。 (过去是我。)

为了使并行处理更轻松,本能地使用它们,我开始开发snidel 。

当您考虑“如何并行?”时, snidel可能是您的选择之一。这对我来说是一种荣幸。

(JA)

我认为有些程序员已经开始使用PHP编程,并通过PHP(我)建立了职业生涯。对于这样的人来说,并行处理可能不熟悉它,或者似乎是一个高阈值。

另外,有些人必须在某种情况下不受PHP以外的其他语言(例如,由于各种情况而具有出色机制的语言)进行开发(例如,我以前是这种情况)。

我们已经开始开发snidel ,目的是使使用并行处理更轻松,直观地解决问题。

我希望snidel可以成为您的选择之一,如果您说:“我想并行执行此过程,我该怎么办?”

通过作曲家安装snidel

 $ composer require ackintosh/ snidel :~0.11.0

建筑学

好处

也可能通过建立功能(例如exec )进行并行处理:

 initialize_data_required_for_the_slow_jobs ();

exec ( ' php slow_job1.php & ' );
exec ( ' php slow_job2.php & ' );

对于以上感到“痛苦”的开发人员, snidel可以提供相当不错的体验,并会简化其PHP编程。

我们将浏览用法,以显示snidel如何并行处理您的编程。使用snidel的经验应解决您的痛苦。让我们开始吧!

用法

基本用法

snidel; $f = function ($s) { sleep(3); echo 'echo: ' . $s; return 'return: ' . $s; }; $s = time(); $ snidel = new snidel (); $ snidel ->process($f, ['foo']); $ snidel ->process($f, ['bar']); $ snidel ->process($f, ['baz']); // ` snidel ::results()` returns `Generator` foreach ($ snidel ->results() as $r) { // string(9) "echo: foo" var_dump($r->getOutput()); // string(11) "return: foo" var_dump($r->getReturn()); } // If you don't need the results, let's use ` snidel ::wait()` instead of ` snidel ::results()` // $ snidel ->wait(); echo (time() - $s) . 'sec elapsed' . PHP_EOL; // 3sec elapsed.">
 
use Ackintosh  snidel ;

$ f = function ( $ s ) {
    sleep ( 3 );
    echo ' echo: ' . $ s ;
    return ' return: ' . $ s ;
};

$ s = time ();
$ snidel = new snidel ();
$ snidel -> process ( $ f , [ ' foo ' ]);
$ snidel -> process ( $ f , [ ' bar ' ]);
$ snidel -> process ( $ f , [ ' baz ' ]);

// ` snidel ::results()` returns `Generator`
foreach ( $ snidel -> results () as $ r ) {
    // string(9) "echo: foo"
    var_dump ( $ r -> getOutput ());
    // string(11) "return: foo"
    var_dump ( $ r -> getReturn ());
}

// If you don't need the results, let's use ` snidel ::wait()` instead of ` snidel ::results()`
// $ snidel ->wait();

echo ( time () - $ s ) . ' sec elapsed ' . PHP_EOL ;
// 3sec elapsed.

构造函数参数

所有参数都是可选的。

snidel([ 'concurrency' => 3, // Please refer to `Logging` 'logger' => $monolog, // Please refer to `Using custom queue` 'driver' => $driver, // a polling duration(in seconds) of queueing 'pollingDuration' => 1, ]);">
 new snidel ([
    ' concurrency ' => 3 ,
    // Please refer to `Logging`
    ' logger ' => $ monolog ,
    // Please refer to `Using custom queue`
    ' driver ' => $ driver ,
    // a polling duration(in seconds) of queueing
    ' pollingDuration ' => 1 ,
]);

call_user_func_array相同的参数

snidel->process($f, ['arg1', 'arg2']); // global function $ snidel ->process('myfunction'); // instance method $ snidel ->process([$instance, 'method']); ">
 // multiple arguments
$ snidel -> process ( $ f , [ ' arg1 ' , ' arg2 ' ]);

// global function
$ snidel -> process ( ' myfunction ' );

// instance method
$ snidel -> process ([ $ instance , ' method ' ]);

标记任务

snidel->process($f, 'arg-A_tag1', 'tag1'); $ snidel ->process($f, 'arg-B_tag1', 'tag1'); $ snidel ->process($f, 'arg_tag2', 'tag2'); foreach ($ snidel ->results as $r) { // `Task::getTag()` returns the tag passed as 3rd parameter of ` snidel ::process()` switch ($r->getTask()->getTag()) { case 'tag1': $r->getReturn(); // arg-A_tag1 | arg-B_tag1 break; case 'tag2': $r->getReturn(); // arg_tag2 break; default: $r->getReturn(); break; } }">
 $ f = function ( $ arg ) {
    return $ arg ;
};

$ snidel -> process ( $ f , ' arg-A_tag1 ' , ' tag1 ' );
$ snidel -> process ( $ f , ' arg-B_tag1 ' , ' tag1 ' );
$ snidel -> process ( $ f , ' arg_tag2 ' , ' tag2 ' );

foreach ( $ snidel -> results as $ r ) {
    // `Task::getTag()` returns the tag passed as 3rd parameter of ` snidel ::process()`
    switch ( $ r -> getTask ()-> getTag ()) {
        case ' tag1 ' :
            $ r -> getReturn (); // arg-A_tag1 | arg-B_tag1
            break ;
        case ' tag2 ' :
            $ r -> getReturn (); // arg_tag2
            break ;
        default :
            $ r -> getReturn ();
            break ;
    }
}

记录

snidel支持使用Logger进行记录,该记录器实现PSR-3:Logger接口。

%level_name% > %message% %context%n")); $monolog->pushHandler($stream); $snidel = new DEBUG > forked worker. pid: 60019 {"role":"master","pid":60017} // 2017-03-22 13:13:43 > DEBUG > has forked. pid: 60018 {"role":"worker","pid":60018} // 2017-03-22 13:13:43 > DEBUG > has forked. pid: 60019 {"role":"worker","pid":60019} // 2017-03-22 13:13:44 > DEBUG > ----> started the function. {"role":"worker","pid":60018} // 2017-03-22 13:13:44 > DEBUG > ----> started the function. {"role":"worker","pid":60019} // ... ">
 // e.g. MonoLog
use Monolog  Formatter  LineFormatter ;
use Monolog  Handler  StreamHandler ;
use Monolog  Logger ;

$ monolog = new Logger ( ' sample ' );
$ stream = new StreamHandler ( ' php://stdout ' , Logger:: DEBUG );
$ stream -> setFormatter ( new LineFormatter ( " %datetime% > %level_name% > %message% %context% n" ));
$ monolog -> pushHandler ( $ stream );

$ snidel = new snidel ([ ' logger ' => $ monolog ]);
$ snidel -> process ( $ f );

// 2017-03-22 13:13:43 > DEBUG > forked worker. pid: 60018 {"role":"master","pid":60017}
// 2017-03-22 13:13:43 > DEBUG > forked worker. pid: 60019 {"role":"master","pid":60017}
// 2017-03-22 13:13:43 > DEBUG > has forked. pid: 60018 {"role":"worker","pid":60018}
// 2017-03-22 13:13:43 > DEBUG > has forked. pid: 60019 {"role":"worker","pid":60019}
// 2017-03-22 13:13:44 > DEBUG > ----> started the function. {"role":"worker","pid":60018}
// 2017-03-22 13:13:44 > DEBUG > ----> started the function. {"role":"worker","pid":60019}
// ...

儿童的错误信息

snidel->process(function ($arg1, $arg2) { exit(1); }, ['foo', 'bar']); $ snidel ->get(); var_dump($ snidel ->getError()); // class Ackintosh snidel Error#4244 (1) { // ... // } foreach ($ snidel ->getError() as $pid => $e) { var_dump($pid, $e); } // int(51813) // array(5) { // 'status' => int(256) // 'message' => string(50) "an error has occurred in child process. // 'callable' => string(9) "*Closure*" // 'args' => // array(2) { // [0] => string(3) "foo" // [1] => string(3) "bar" // } // 'return' => NULL // } // }">
 $ snidel -> process ( function ( $ arg1 , $ arg2 ) {
    exit ( 1 );
}, [ ' foo ' , ' bar ' ]);
$ snidel -> get ();

var_dump ( $ snidel -> getError ());
// class Ackintosh snidel Error#4244 (1) {
// ...
// }

foreach ( $ snidel -> getError () as $ pid => $ e ) {
    var_dump ( $ pid , $ e );
}
// int(51813)
// array(5) {
//   'status' =>  int(256)
//   'message' => string(50) "an error has occurred in child process.
//   'callable' => string(9) "*Closure*"
//   'args' =>
//     array(2) {
//       [0] => string(3) "foo"
//       [1] => string(3) "bar"
//     }
//   'return' => NULL
//   }
// }

使用自定义队列

snidel取决于Bernard作为队列抽象层。伯纳德(Bernard)是一个多余的PHP库,用于创建背景作业以供以后处理。
默认情况下, snidel构建了Flatfile驱动程序,但是从种族条件的角度来看,我们建议在生产中使用更可靠的队列。

Amazon SQS
snidel([ 'driver' => $driver, ]);">
 $ connection = Aws  Sqs SqsClient:: factory ([
    ' key '    => ' your-aws-access-key ' ,
    ' secret ' => ' your-aws-secret-key ' ,
    ' region ' => ' the-aws-region-you-choose '
]);
$ driver = new Bernard  Driver  SqsDriver ( $ connection );

new snidel ([
    ' driver ' => $ driver ,
]);

有关驾驶员的详细信息,请参阅此处。

文章

这是引入snidel的文章。谢谢你!

  • [php-都

要求

  • PCNTL功能

版本指导

snidel php
0.1〜0.8 > = 5.3
0.9〜 > = 5.6
0.13 > = 7.1

Docker

我们建议您尝试使用Docker,因为snidel需要需求中显示的一些PHP扩展。

在Docker容器中运行单元测试

snidel . docker run --rm -v ${PWD}:/ snidel snidel php composer.phar install docker run --rm -v ${PWD}:/ snidel snidel vendor/bin/phpunit">
curl -Ss https://get*comp**oser.org/installer | php
docker build -t snidel .
docker run --rm -v ${PWD} :/ snidel snidel php composer.phar install
docker run --rm -v ${PWD} :/ snidel snidel vendor/bin/phpunit

作者

snidel ©Ackintosh,根据MIT许可证发布。
由Ackintosh撰写和维护

github @ackintosh / twitter @nakano_akihito / blog(ja)

作者关于snidel (JA)的博客条目:

  • https://ackintosh.g*ith**ub.io/blog/2015/09/29/snidel/
  • https://ackintosh.g**i*thub.io/blog/2015/11/08/snidel_0_2_0/
  • https://ackintosh.g**it*hub.io/blog/2016/04/04/snidel_0_4_0/
  • https://ackintosh.gi***thub.io/blog/2016/04/04/snidel_0_5_0/
  • https://ackintosh.**gi*thub.io/blog/2016/05/04/snidel_0_6_0/
  • https://ackintosh.gi**th*ub.io/blog/2016/09/09/snidel_0_7_0/
  • https://ackintosh.g*i*thu*b.io/blog/2017/03/10/snidel_0_8_0/
  • https://ackintosh.g**it*hub.io/blog/2017/07/17/snidel_0_9_0/

致谢

感谢Jetbrains提供免费的开源许可证。

下载源码

通过命令行克隆项目:

git clone https://github.com/ackintosh/snidel.git