Почему чтение из конвейера блокирует процесс? - PullRequest
1 голос
/ 14 июня 2019

У меня есть два процесса (оба .NET Framework приложения), и я пытаюсь связаться с помощью Named Pipes Клиент подключается к каналу, но когда он пытается ReadAsync сообщение, отправленное сервером, он начинает ждать индиффинно, даже если сервер уже отправил сообщение !!

Что меня удивляет, так это то, что если я закрою приложение Server, то Client наконец продолжит доследующая строка кода (после строки ReadAsync), прочитав 0 байт.

Есть ли что-то, что я должен сделать на сервере после WriteAsync -ing полезной нагрузки?Нужно ли сбрасывать или что-нибудь?

Сервер

static async Task Main(string[] args) {

         var server = new NamedPipeServerStream(
             "somePipe",
              PipeDirection.InOut, 
              2, 
              PipeTransmissionMode.Message
              );

         await server.WaitForConnectionAsync();

         using (StreamReader reader = new StreamReader(server)) {
              using (StreamWriter writer = new StreamWriter(server)) {

                 await writer.WriteAsync("Hello from server"); 

                 char[] buffer = new char[20];
                 var read = await reader.ReadAsync(buffer, 0, buffer.Length);
                }
         }
}

Клиент

 static async Task Main() {

    NamedPipeClientStream client = new NamedPipeClientStream(
             ".",
             "somePipe",
             PipeDirection.InOut,
             PipeOptions.Asynchronous);

    await client.ConnectAsync();

    try {
    using (StreamReader reader = new StreamReader(client)) {
        using (StreamWriter writer = new StreamWriter(client)) {

          var buffer = new char[20];
          int readChars = await reader.ReadAsync(buffer, 0,buffer.Length); //starts waiting indifinetly , until i close the Server

          await writer.WriteAsync("From Client");

        }
     }
     } catch (Exception ex) {

       throw;
     }
}

Обновление Кажется, использование NamedPipeServerStream непосредственно для записи вместо StreamWriter на стороне сервера заставляет клиента получать данные!

Изменения сервера

byte[] data=Encoding.UTF8.GetBytes("Hello from server");
server.WriteAsync(data,0,data.Length);

PS Однако повторное использование server до ReadAsync блокирует сервер. Таким образом, существует проблема при переносе NamedPipeServerStream и ClientStream в StreamReader и StreamWriter.

1 Ответ

1 голос
/ 18 июня 2019

Эта проблема с блокировкой / блокировкой вызвана тем, что код, сгенерированный под прикрытием синтаксическим сахаром async / await.Если вы не добавите ConfigureAwait(false), компилятор сгенерирует что-нибудь интересное для приложения с пользовательским интерфейсом (UI - это общий термин, может быть ASP.NET - не ядро ​​-, WPF, Winforms и т. Д.), Но это может быть смертельно опаснымв противном случае.

A лот переписан по этому вопросу:

Не блокировать асинхронный код

цитируется:

Существует две передовые практики, [...] которые позволяют избежать этой ситуации:

  • В асинхронных методах вашей «библиотеки» используйте ConfigureAwait (false), где это возможно.
  • Не блокировать задачи;использовать async до конца.

Параллельные вычисления - это все о SynchronizationContext

Рекомендуется вызывать ConfigureAwait для всех серверовкод стороны

Должен ли я вызывать ConfigureAwait (false) при каждой ожидаемой операции

Итак, самое простое решение - добавить ConfigureAwait(false) везде в вашем коде, который, как известно, не запускается в пользовательском интерфейсе или не использует async везде (никогда не блокируйте никакие задачи во всем вашем коде, действительно везде, в том числе в коде, который вы не делаетесобственные).

ИМХО, это смешно ... Я лично использую расширение Visual Studio, которое кричит на меня, если я забуду добавить его после каждого async вызова: -)

Обратите внимание, что есть несколько альтернатив, например: Альтернатива ConfigureAwait (false) везде

...