Swoole-src: Trying to improve concurrency on server

Created on 13 Nov 2019  路  4Comments  路  Source: swoole/swoole-src

Please answer these questions before submitting your issue. Thanks!

  1. What did you do? If possible, provide a simple script for reproducing the error.
<?php
$http = new swoole_http_server("127.0.0.1", 9501, SWOOLE_PROCESS);

$http->set([
    'worker_num' => 1,
    'dispatch_mode' => 1,
]);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) use ($http) {
    $response->header('Content-Type', 'application/pdf');

    $fd = fopen('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', 'r');

    while(!feof($fd)) {
        $data = fread($fd, 1024);

        // some long process with $data
        sleep(1);

        !empty($data) && $response->write($data);

        // Uncomment to achieve paralelism
        // co::sleep(0.001);

        if (!$http->exist($response->fd)) {
            throw new \Exception('Client lost');
        }
    }

    $response->end();
});

$http->start();

  1. What did you expect to see?

I'm expecting to be able to start 2 or more downloads (ie: curl http://localhost:9501 -o test1.pdf) after some processing on a remote file (reading + encrypting + writing on response).

  1. What did you see instead?

The number of simultaneous downloads is limited by the worker_num.

With co::sleep, I'm able to get paralelism because co::sleep allows to the scheduler to use the cpu for another coroutines. The problem is that with co::sleep I'm getting a lower download rate, possible due the interruptions.

Is there another way to _"invite"_ to the scheduler to switch to another coroutines?

Congratulations by the amazing work you've done.

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

swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.2.13
Built => Aug  6 2019 13:14:08
coroutine => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.0.2r  26 Feb 2019
pcre => enabled
zlib => enabled
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
async_redis => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608
  1. What is your machine environment used (including version of kernel & php & gcc) ?
$ php -v
PHP 7.3.7 (cli) (built: Aug  6 2019 11:40:40) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.7, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.7, Copyright (c) 1999-2018, by Zend Technologies
$ uname -r
4.19.57-gentoo
$ gcc --version
gcc (Gentoo 8.3.0-r1 p1.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
question

Most helpful comment

<?php
\Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
$http = new swoole_http_server("127.0.0.1", 9501, SWOOLE_PROCESS);

$http->set([
    'worker_num'    => 1,
    'dispatch_mode' => 1,
]);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) use ($http) {
    $response->header('Content-Type', 'application/pdf');

    $fd = fopen('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', 'r');

    while (!feof($fd)) {
        $data = fread($fd, 1024);

        // some long process with $data
        sleep(1);

        !empty($data) && $response->write($data);

        // Uncomment to achieve paralelism
        // co::sleep(0.001);

        if (!$http->exist($response->fd)) {
            throw new \Exception('Client lost');
        }
    }

    $response->end();
});

$http->start();

All 4 comments

you are using synchronous read in your handler. change to async

Please answer these questions before submitting your issue. Thanks!

  1. What did you do? If possible, provide a simple script for reproducing the error.
<?php
$http = new swoole_http_server("127.0.0.1", 9501, SWOOLE_PROCESS);

$http->set([
    'worker_num' => 1,
    'dispatch_mode' => 1,
]);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) use ($http) {
    $response->header('Content-Type', 'application/pdf');

    $fd = fopen('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', 'r');

    while(!feof($fd)) {
        $data = fread($fd, 1024);

        // some long process with $data
        sleep(1);

        !empty($data) && $response->write($data);

        // Uncomment to achieve paralelism
        // co::sleep(0.001);

        if (!$http->exist($response->fd)) {
            throw new \Exception('Client lost');
        }
    }

    $response->end();
});

$http->start();
  1. What did you expect to see?

I'm expecting to be able to start 2 or more downloads (ie: curl http://localhost:9501 -o test1.pdf) after some processing on a remote file (reading + encrypting + writing on response).

  1. What did you see instead?

The number of simultaneous downloads is limited by the worker_num.

With co::sleep, I'm able to get paralelism because co::sleep allows to the scheduler to use the cpu for another coroutines. The problem is that with co::sleep I'm getting a lower download rate, possible due the interruptions.

Is there another way to _"invite"_ to the scheduler to switch to another coroutines?

Congratulations by the amazing work you've done.

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

swoole

Swoole => enabled
Author => Swoole Team <[email protected]>
Version => 4.2.13
Built => Aug  6 2019 13:14:08
coroutine => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
cpu_affinity => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.0.2r  26 Feb 2019
pcre => enabled
zlib => enabled
mutex_timedlock => enabled
pthread_barrier => enabled
futex => enabled
async_redis => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.display_errors => On => On
swoole.use_shortname => On => On
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608
  1. What is your machine environment used (including version of kernel & php & gcc) ?
$ php -v
PHP 7.3.7 (cli) (built: Aug  6 2019 11:40:40) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.3.7, Copyright (c) 1998-2018 Zend Technologies
    with Zend OPcache v7.3.7, Copyright (c) 1999-2018, by Zend Technologies
$ uname -r
4.19.57-gentoo
$ gcc --version
gcc (Gentoo 8.3.0-r1 p1.1) 8.3.0
Copyright (C) 2018 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

hi,please open the runtime hook.
like this:
\Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);

<?php
\Swoole\Runtime::enableCoroutine(true, SWOOLE_HOOK_ALL);
$http = new swoole_http_server("127.0.0.1", 9501, SWOOLE_PROCESS);

$http->set([
    'worker_num'    => 1,
    'dispatch_mode' => 1,
]);

$http->on('start', function ($server) {
    echo "Swoole http server is started at http://127.0.0.1:9501\n";
});

$http->on('request', function ($request, $response) use ($http) {
    $response->header('Content-Type', 'application/pdf');

    $fd = fopen('https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf', 'r');

    while (!feof($fd)) {
        $data = fread($fd, 1024);

        // some long process with $data
        sleep(1);

        !empty($data) && $response->write($data);

        // Uncomment to achieve paralelism
        // co::sleep(0.001);

        if (!$http->exist($response->fd)) {
            throw new \Exception('Client lost');
        }
    }

    $response->end();
});

$http->start();

The line added makes the difference.

Thank you very much.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

nick-zh picture nick-zh  路  3Comments

sagesan picture sagesan  路  4Comments

AndyChanCode picture AndyChanCode  路  3Comments

sshymko picture sshymko  路  3Comments

pthreat picture pthreat  路  3Comments