Пример асинхронной передачи данных через потоки данных

Можете показать пример, как написать 2 асинхронные задачи, чтобы они использовали один и тот же Stream (одна пишет, другая читает)? Ну и еще я хочу иметь возможность закинуть их в одну коллекцию и вызвать через Task.WhenAll(). При этом нужно чтобы записывающая таска не писала все данные разом, а отсылала их кусками. Пример:

private static async Task Write(Stream stream)
{
    var writer = new StreamWriter(stream);
    await writer.WriteAsync("aba");
    await Task.Delay(1000);
    await writer.WriteAsync("caba");
}
using var stream = new MemoryStream();
var tasks = new[] { Write(stream), Read(stream) };
await Task.WhenAll(tasks);
Console.WriteLine("Finished");

Результат должен выглядеть, например, чтобы в консоль сначала вывело "aba" (ну или не целиком, пусть это определяется размером буфера) и спустя секунду - оставшаяся часть строки

Как должен выглядеть метод Read? Или я использую нежизнеспособный подход и задача об асинхронном использовании стрима решается как-то иначе?

Естественно, выгружать условную строку в оперативную память целиком - не вариант, я использую стримы как раз для того чтобы обрабатывать переданные данные динамически


Ответы (1 шт):

Автор решения: aepot

Судя по задаче, вы выбрали неверный инструмент. Для того что вам нужно, используется другой класс - Channel.

static async Task Main(string[] args)
{
    Channel<string> channel = Channel.CreateUnbounded<string>();
    await Task.WhenAll(ReadAsync(channel.Reader), WriteAsync(channel.Writer));
}

static async Task ReadAsync(ChannelReader<string> reader)
{
    await foreach (string text in reader.ReadAllAsync())
    {
        Console.Write(text);
    }
}

static async Task WriteAsync(ChannelWriter<string> writer)
{
    await writer.WriteAsync("aba");
    await Task.Delay(1000);
    await writer.WriteAsync("caba");
    writer.Complete(); // сообщает каналу, что данных больше нет, чтобы Reader завершился
}
→ Ссылка