swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.25k stars 3.16k forks source link

开启一键协程化之后, `proc_open()` 似乎会受到先前空方法体的 `run(function() {});` 的影响。 #5315

Closed vkviyu closed 1 week ago

vkviyu commented 1 week ago

Please answer these questions before submitting your issue.

  1. What did you do? If possible, provide a simple script for reproducing the error. 当我使用 Swoole\Coroutine::enableCoroutine() 之后,直接使用 proc_open('php -v', [], $pipes); , 不开启任何协程环境,会报错。这样子看上去应该是合理的,报错输出如下所示:
    
    [root@hcss-ecs-e746 bin]# php doctrine.php 

Fatal error: Uncaught Swoole\Error: API must be called in the coroutine in /root/www/xy-workerman/components/database/doctrine/bin/doctrine.php:29 Stack trace:

0 /root/www/xy-workerman/components/database/doctrine/bin/doctrine.php(29): proc_open('php -v', Array, NULL)

1 {main}

thrown in /root/www/xy-workerman/components/database/doctrine/bin/doctrine.php on line 29

但是当我在 `proc_open('php -v', [], $pipes);` 前面加上一个 `run(function() {})` 这样一个方法体为空的协程之后,原先的错误就消失了。如下所示:
```php
<?php

/**
 * doctrine 命令行工具
 */
require_once __DIR__ . '/../../../../vendor/autoload.php';
use function Co\run;

// Runtime::getInstance()->boot(
//     [
//         'doctrine' => new Strategy(__DIR__ . '/config/doctrine_redis.yaml')
//     ],
// );
\Swoole\Runtime::enableCoroutine();
run(function () {

});
// $entityManager = Runtime::getInstance()->getService('doctrine.entity_manager', 'doctrine');
// var_dump($entityManager);

// $commands = [
//     // ...
// ];
// var_dump(Swoole\Coroutine::getPcid());
proc_open('php -v', [], $pipes);

// Swoole\Coroutine::sleep(1);
// ConsoleRunner::run(
//     new SingleManagerProvider($entityManager),
//     $commands
// );
  1. What did you expect to see? 我认为 run(function(){}) 方法体之外应该已经不属于协程环境中了,为何加了一个空的 run(function(){}) 之后原先的:Fatal error: Uncaught Swoole\Error: API must be called in the coroutine in /root/www/xy-workerman/components/database/doctrine/bin/doctrine.php:29 保存就不存在,正常情况下这个错误应该不会因为加了一个空的 `run(function(){}) 就得到解决吧。

  2. What did you see instead? run(function(){}) 尽管方法体为空且已经结束了,但是可能仍然保留了一些协程环境的状态?但是当我使用 var_dump(Swoole\Coroutine::getcid()); 时输出的结果为 -1 ,应该已经不在协程环境中了,可是因为加了一个空的 run(function(){}),Fatal error: Uncaught Swoole\Error: API must be called in the coroutine in /root/www/xy-workerman/components/database/doctrine/bin/doctrine.php:29 这段报错就得到了解决。

  3. What version of Swoole are you using (show your php --ri swoole)?

    
    [root@hcss-ecs-e746 bin]# php --ri swoole

swoole

Swoole => enabled Author => Swoole Team team@swoole.com Version => 5.1.1 Built => Feb 23 2024 08:43:10 coroutine => enabled with boost asm context epoll => enabled eventfd => enabled signalfd => enabled cpu_affinity => enabled spinlock => enabled rwlock => enabled sockets => enabled openssl => OpenSSL 3.1.4+quic 24 Oct 2023 dtls => enabled http2 => enabled json => enabled curl-native => enabled c-ares => 1.24.0 zlib => 1.3.1 brotli => E16777225/D16777225 mutex_timedlock => enabled pthread_barrier => enabled futex => enabled mysqlnd => enabled async_redis => enabled coroutine_pgsql => enabled coroutine_odbc => enabled coroutine_sqlite => enabled

Directive => Local Value => Master Value swoole.enable_coroutine => On => On swoole.enable_library => On => On swoole.enable_fiber_mock => Off => Off swoole.enable_preemptive_scheduler => Off => Off swoole.display_errors => On => On swoole.use_shortname => On => On swoole.unixsock_buffer_size => 8388608 => 8388608


Swoole-cli 版本:Swoole 5.1.1 (cli) (built: Feb 23 2024 08:45:06) (NTS)

5. What is your machine environment used (show your `uname -a` & `php -v` & `gcc -v`) ?
Swoole 5.1.1 (cli) (built: Feb 23 2024 08:45:06) (NTS)
NathanFreeman commented 1 week ago

因为Swoole\Coroutine::enableCoroutine()除了设置标志位之外,还提前替换了阻塞函数为非阻塞函数。 run(function () {});执行完毕也就意味着协程已经结束了,会在退出阶段将阻塞函数复原回来。