Skip to content

Implement asynchronous server#17

Merged
thekid merged 10 commits intomasterfrom
feature/async
Mar 31, 2021
Merged

Implement asynchronous server#17
thekid merged 10 commits intomasterfrom
feature/async

Conversation

@thekid
Copy link
Copy Markdown
Member

@thekid thekid commented Mar 29, 2021

It supports protocols where handleData() returns a generator function to yield back control to the server, e.g. during lengthy up- or download operations. Here's a web application showcasing this:

<?php

use io\File;
use web\Application;

class Hello extends Application {

  public function routes() {
    return [
      '/download' => function($req, $res) {
        $target= new File('download.mp4');
        $target->open(File::READ);

        $res->answer(200, 'OK');
        $res->header('Content-Type', 'video/mp4');

        try {
          $out= $res->stream($target->size());
          do {
            $out->write($target->read(16384));
            yield;
          } while (!$target->eof());
        } finally {
          $target->close();
        }
      },
      '/block' => function($req, $res) {
        $target= new File('download.mp4');
        $res->transfer($target->in(), 'video/mp4', $target->size());
      },
      '/' => function($req, $res) {
        $res->answer(200, 'OK');
        $res->send('Hello World', 'text/plain');
      },
    ];
  }
}

For backwards compatibility, this is implemented in a new server class called peer.server.AsyncServer. However, this will become the default with the next major release.

thekid added 3 commits March 29, 2021 19:47
It supports protocols where handleData() returns a generator function to yield
back control to the server, e.g. during lengthy up- or download operations.

For backwards compatibility, this is implemented in a new server class called
peer.server.AsyncServer. However, this will become the default with the next
major release
[$protocol, 'handleDisconnect'],
[$protocol, 'handleError'],
[$protocol, 'initialize']
];
Copy link
Copy Markdown
Member Author

@thekid thekid Mar 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Isn't this slow?" - I thought - indirectly invoking methods via an array?

use peer\Socket;
use util\profiling\Timer;

class Protocol {

  public function handleData($socket) {
    return $socket->toString();
  }
}

$protocol= new Protocol();
$invoke= [[$protocol, 'handleData']];
$socket= new Socket('127.0.0.1', 8080);

$timer= (new Timer())->start();
for ($i= 0; $i < 10_000_000; $i++) {
  // $result= ($f= $invoke[0] ?? null) ? $f($socket) : null;
  $result= $protocol->handleData($socket);
}

printf("%.3f seconds: %s\n", $timer->elapsedTime(), $result);
  • Indirect: 5.791 seconds: peer.Socket((closed) -> tcp://127.0.0.1:8080)
  • Direct: 4.877 seconds: peer.Socket((closed) -> tcp://127.0.0.1:8080)

So yes, this is one second difference, but for 10 million invocations (so only 1_000 / 10_000_000 = 0.0001 milliseconds difference per invocation)! Compared to the socket I/O we're handling

Comment thread src/main/php/peer/server/AsyncServer.class.php
Comment thread src/main/php/peer/server/AsyncServer.class.php Outdated
@thekid thekid merged commit c87d352 into master Mar 31, 2021
@thekid thekid deleted the feature/async branch March 31, 2021 14:45
@thekid
Copy link
Copy Markdown
Member Author

thekid commented Mar 31, 2021

thekid added a commit to xp-forge/web that referenced this pull request Jul 6, 2025
See xp-framework/networking#17 (released in 10.1.0, the minimum version we depend on)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant