发送数据协程调度

现状

现在 Server/Client->send 在缓存区已满的情况下,会直接返回false,需要借助onBufferFullonBufferEmpty这样复杂的事件通知机制才能实现任务的暂停和恢复。

在实现需要大量发送的场景下,现有机制虽然可以实现,但非常复杂。

思路

现在基于协程可以实现一种机制,直接在当前协程内yield,等待数据发送完成,缓存区清空时,自动resume当前协程,继续send数据。

  • Server/Client->send返回false并且错误码为SW_ERROR_OUTPUT_BUFFER_OVERFLOW时,不返回falsephp层,而是yield挂起当前协程
  • Server/Client监听onBufferEmpty事件,在该事件触发后,缓存区内的数据已被发送完毕,这时resume对应的协程
  • 协程恢复后,继续调用Server/Client->send向缓存区内写入数据,这时因为缓存区已空,发送必然是成功的

实例

改进前

  1. for ($i = 0; $i < 100; $i++)
  2. {
  3. //在缓存区塞满时会直接返回`false`
  4. $server->send($fd, $data_2m);
  5. }

改进后

  1. for ($i = 0; $i < 100; $i++)
  2. {
  3. //在缓存区塞满时会 yield 当前协程,发送完成后 resume 继续向下执行
  4. $server->send($fd, $data_2m);
  5. }

选项

此项特性会改变底层的默认行为,因此需要额外的一个参数来开启。

  1. $serv->set([
  2. 'send_yield' => true,
  3. ]);

影响范围

  • Swoole\Server::send
  • Swoole\Http\Response::write
  • Swoole\WebSocket\Server::push
  • Swoole\Coroutine\Client::send
  • Swoole\Coroutine\Http\Client::push