Компоненти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";
});

Дивіться також ​