组件ThreadChannel::send()

ThreadChannel::send

(PHP 8.6+, True Async 1.0)

php
public ThreadChannel::send(mixed $value, ?Completable $cancellationToken = null): void

向通道发送值。这是一个阻塞操作 — 如果通道无法立即接受值,调用线程将被阻塞。

  • 对于无缓冲通道capacity = 0),线程阻塞直到另一个线程调用 recv()
  • 对于有缓冲通道,只有当缓冲区已满时线程才会阻塞,一旦接收方取走一个槽位即解除阻塞。

Channel::send()(挂起协程)不同,ThreadChannel::send() 会阻塞整个操作系统线程。请相应地设计架构 — 例如,保持发送线程可以自由阻塞,或使用有缓冲通道来减少争用。

值在放入通道之前会被深拷贝。闭包、资源以及无法序列化的对象将导致 ThreadTransferException

参数

value : 要发送的值。可以是任何可序列化类型(标量、数组或可序列化对象)。

错误

  • 如果通道已关闭,抛出 Async\ThreadChannelException
  • 如果值无法序列化以进行跨线程传输,抛出 Async\ThreadTransferException

示例

示例 #1 从工作线程发送结果

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $channel = new ThreadChannel(5);

    $worker = spawn_thread(function() use ($channel) {
        for ($i = 1; $i <= 5; $i++) {
            $result = $i * $i;
            $channel->send($result);
        }
        $channel->close();
    });

    await($worker);

    while (!$channel->isClosed() || !$channel->isEmpty()) {
        try {
            echo $channel->recv(), "\n";
        } catch (\Async\ThreadChannelException) {
            break;
        }
    }
});

示例 #2 线程间的无缓冲握手

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $requests  = new ThreadChannel(); // 无缓冲
    $responses = new ThreadChannel();

    $server = spawn_thread(function() use ($requests, $responses) {
        $req = $requests->recv();             // 阻塞直到请求到来
        $responses->send(strtoupper($req));   // 阻塞直到响应被接受
    });

    $requests->send('hello');                 // 阻塞直到服务器调用 recv()
    $reply = $responses->recv();              // 阻塞直到服务器调用 send()
    await($server);

    echo $reply, "\n"; // "HELLO"
});

示例 #3 处理已关闭的通道

php
<?php

use Async\ThreadChannel;
use function Async\spawn;
use function Async\spawn_thread;
use function Async\await;

spawn(function() {
    $channel = new ThreadChannel(1);
    $channel->close();

    $thread = spawn_thread(function() use ($channel) {
        try {
            $channel->send('too late');
        } catch (\Async\ThreadChannelException $e) {
            return "Send failed: " . $e->getMessage();
        }
    });

    echo await($thread), "\n";
});

参见