为什么从管道读取会阻塞进程?
Why does reading from pipe block the process?
我有两个进程(都是 .NET Framework
应用程序),我正在尝试使用 Named Pipes
进行通信
客户端连接到管道,但是当它尝试 ReadAsync
服务器发送的消息时,它开始无休止地等待,即使服务器已经发送了消息!!
令我惊讶的是,如果我关闭 Server
应用程序,Client
最终 继续 到下一行代码(在 ReadAsync
行),已读取 0 字节。
在 WriteAsync
加载负载后,我必须在服务器上做些什么吗?我需要冲洗什么吗?
服务器
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);
P.S
但是,再次使用 server
到 ReadAsync
会阻塞 server.So 将 NamedPipeServerStream
和 ClientStream
包装到 StreamReader
和 [=21 时会出现问题=].
此 blocking/lock 问题是由 async/await 语法糖暗中生成的代码引起的。
如果你不添加 ConfigureAwait(false)
,编译器会生成一些对 UI 应用程序很酷的东西(UI 是一个通用术语,可能是 ASP.NET - 不是核心 - ,WPF , Winforms 等),否则可能会致命。
一个 lot 已经写了关于此事的文章:
引用:
There are two best practices [...] that avoid this situation:
- In your “library” async methods, use ConfigureAwait(false) wherever
possible.
- Don’t block on Tasks; use async all the way down.
Parallel Computing - It's All About the SynchronizationContext
Best practice to call ConfigureAwait for all server-side code
Should I call ConfigureAwait(false) on every awaited operation
因此,最简单的解决方案是在 UI 中 运行 不知道的代码中的所有地方 添加 ConfigureAwait(false)
,或使用 async
everywhere(永远不要在你的整个代码中阻塞任何任务,真的无处不在,包括在你不拥有的代码中)。
恕我直言,这太荒谬了...我个人使用一个 Visual Studio 扩展,如果我忘记在每个 async
调用后面添加它,它就会对我大吼大叫 :-)
注意有一些替代方案,例如:
An alternative to ConfigureAwait(false) everywhere
我有两个进程(都是 .NET Framework
应用程序),我正在尝试使用 Named Pipes
进行通信
客户端连接到管道,但是当它尝试 ReadAsync
服务器发送的消息时,它开始无休止地等待,即使服务器已经发送了消息!!
令我惊讶的是,如果我关闭 Server
应用程序,Client
最终 继续 到下一行代码(在 ReadAsync
行),已读取 0 字节。
在 WriteAsync
加载负载后,我必须在服务器上做些什么吗?我需要冲洗什么吗?
服务器
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);
P.S
但是,再次使用 server
到 ReadAsync
会阻塞 server.So 将 NamedPipeServerStream
和 ClientStream
包装到 StreamReader
和 [=21 时会出现问题=].
此 blocking/lock 问题是由 async/await 语法糖暗中生成的代码引起的。
如果你不添加 ConfigureAwait(false)
,编译器会生成一些对 UI 应用程序很酷的东西(UI 是一个通用术语,可能是 ASP.NET - 不是核心 - ,WPF , Winforms 等),否则可能会致命。
一个 lot 已经写了关于此事的文章:
引用:
There are two best practices [...] that avoid this situation:
- In your “library” async methods, use ConfigureAwait(false) wherever possible.
- Don’t block on Tasks; use async all the way down.
Parallel Computing - It's All About the SynchronizationContext
Best practice to call ConfigureAwait for all server-side code
Should I call ConfigureAwait(false) on every awaited operation
因此,最简单的解决方案是在 UI 中 运行 不知道的代码中的所有地方 添加 ConfigureAwait(false)
,或使用 async
everywhere(永远不要在你的整个代码中阻塞任何任务,真的无处不在,包括在你不拥有的代码中)。
恕我直言,这太荒谬了...我个人使用一个 Visual Studio 扩展,如果我忘记在每个 async
调用后面添加它,它就会对我大吼大叫 :-)
注意有一些替代方案,例如: An alternative to ConfigureAwait(false) everywhere