假设我在 .NET 中使用数据流块。据说“这个数据流模型促进了基于参与者的编程”,这正是我想要在这里得到的。
但是,如果我处理来自 aBufferBlock<T>
和消息处理器中的消息,我决定使用async
/ await
,这会将执行分叉到当前线程和等待任务的工作线程。
有什么方法可以防止参与者/消息处理器中的并发执行吗?
如果等待的任务使用带有本机回调的非阻塞 IO 操作执行,那很好。但我真的很想确保任何 .NET 代码只同步执行。
假设我在 .NET 中使用数据流块。据说“这个数据流模型促进了基于参与者的编程”,这正是我想要在这里得到的。
但是,如果我处理来自 aBufferBlock<T>
和消息处理器中的消息,我决定使用async
/ await
,这会将执行分叉到当前线程和等待任务的工作线程。
有什么方法可以防止参与者/消息处理器中的并发执行吗?
如果等待的任务使用带有本机回调的非阻塞 IO 操作执行,那很好。但我真的很想确保任何 .NET 代码只同步执行。
这在很大程度上取决于您将如何处理这些消息。
如果你使用ActionBlock
with async
action
,不要设置它MaxDegreeOfParallelism
(这意味着使用默认值 1 )并将其链接到BufferBlock
,然后action
将一次执行一条消息,不会有并行性。
如果您使用这样的循环手动处理消息:
while (await bufferBlock.OutputAvailableAsync())
{
var message = await bufferBlock.ReceiveAsync();
await ProcessMessageAsync(message);
}
然后消息也将一次处理一个。
但在这两种情况下,并不意味着一条消息将由单个线程处理。它可以由多个线程处理,但不能并行处理。这是因为在 之后await
,执行可以在与暂停位置不同的线程上恢复。
如果您使用其他处理消息的方式(例如,使用上面的循环,但省略了await
before ProcessMessageAsync()
),则可以同时处理多条消息。
你误解了什么await
。它不派生任何东西,它只是等待已经异步操作的结果。
用关键字标记的方法async
不会自动变为异步的。只有在方法内部遇到异步操作时,才会异步async
继续执行。关键字只是告诉编译器在异步操作完成后应该在async
哪里继续执行。
等待时不会浪费或损坏 ThreadPool 线程,因此您不应该试图限制、阻止或规避这一点。事实上,使用异步操作时,您可以获得更好的可伸缩性,因为 TPL 数据流使用的 ThreadPool 线程不会阻塞等待长时间运行的异步操作,如 I/O 或 Web 服务调用。