php.exe可以连续运行数周或数月的应用程序运行,而不会崩溃吗?

Gar*_*ary 0 php networking events pthreads long-running-processes

php.exe可以连续运行数周或数月的应用程序运行,而不会崩溃吗?

例如:UDP或HTTP/TCP服务器(或网络)应用程序.我听说它还没有为长时间运行的应用程序开发.我相信我们可以在linux和Windows中使用pthreads/events来进行多线程/并行,以支持为进程生成的负载并开发长时间运行的应用程序.但不确定会有多稳定.任何能够使用pthreads和长期运行的PHP应用程序发表评论并提供开发资源指导的人?

Joe*_*ins 6

PHP

低于5.3的PHP版本没有垃圾收集器,这导致看似简单的代码(循环,递归)消耗大量内存:

<?php
class Foo
{
    public $var = '3.14159265359';
}

$baseMemory = memory_get_usage();

for ( $i = 0; $i <= 100000; $i++ )
{
    $a = new Foo;
    $a->self = $a;
    if ( $i % 500 === 0 )
    {
        echo sprintf( '%8d: ', $i ), memory_get_usage() - $baseMemory, "\n";
    }
}
?>
Run Code Online (Sandbox Code Playgroud)

以下是5.2和5.3并排的内存使用情况:

5.2 vs 5.3内存使用情况

这使得编写任何复杂性的代码无限期地运行,因为在5.3以下的PHP版本中没有任何区别.

对于等于或大于5.3的PHP版本,Zend绝对没有禁止执行长时间运行的脚本,甚至是无限期执行.

还有一些事情要考虑; 如果无限附加到某个数组,则需要无限量的内存来存储该数组.

只需要小心,即使无害的变化也会对消费产生影响,因此在开发过程中建立频繁回归测试的模式,以便您可以立即看到问题的引入位置.

PHP手册中获取的代码和图像.

pthreads v3

我将在pthreads v3,PHP7 +的上下文中回答.

pthreads可能会消耗比您预期更多的内存.PHP是一个无共享的环境,pthreads不能破坏该体系结构,因此与普通的多线程应用程序不同,线程不能共享相同的地址空间.

pthreads使它看起来好像它们一样,它的方式对答案来说并不重要.

通过正常的Thread编程,消耗不应该如此难以控制,但是使用WorkerPool编程,它可能不那么明显.

请使用以下代码:

<?php
class Job extends Threaded {
    public function run() {
        printf("Job in Thread %lu (%d) bytes\n",
            Thread::getCurrentThreadId(),
            memory_get_usage(false));
    }
}

$pool = new Pool(16);
$monitor = new Threaded();

do {
    for ($i=0; $i<100; $i++)
        $pool->submit(new Job());   

    while ($pool->collect())
        continue;

    printf("Main context (%d) bytes\n",
        memory_get_usage(false));

    $monitor->synchronized(function() use($monitor) {
        $monitor->wait(1000000);
    }); 
} while (true);
?>
Run Code Online (Sandbox Code Playgroud)

使用的调用$monitor应该是约定,这是强制一个Thread甚至主要上下文睡眠的最好方法.

如果没有拨打电话::collect,消费很快就会失控.

::collect方法实际上是Worker类的一部分,Pool它通过代理为Worker它正在使用的所有对象调用它.

原型可以被视为:

public function collect(callable $collector = Worker::collector);
Run Code Online (Sandbox Code Playgroud)

Job从队列中弹出a 以便在Worker执行它的上下文中执行时,它将被插入到垃圾列表中.

::collect调用时,Worker遍历的垃圾列表,将每个传递Job$collector传递(或不传递)作为参数.

如果Worker正在进行的那种工作会使当时收集垃圾变得危险,那么调用::collect将提前返回,如果返回值为::collect> 0 ,则应该再次尝试.

$collector应该返回true,如果Job能够从垃圾列表中删除(因此释放相关资源,如果不存在其他的引用),默认的Worker::collector收益true,假设在垃圾列表中的对象是准备销毁尽早.

所有这些都允许长时间运行,相当复杂的基于pthreads的应用程序无限期运行.

必须考虑与普通PHP相同的考虑因素,还需要额外的(一点点)腿部工作.