According to MSDN, async
và await
không tạo chủ đề mới:Hiểu async/chờ đợi mà không đề
Các
async
vàawait
từ khóa không gây đề bổ sung để được tạo ra.
Với ý nghĩ này, tôi gặp khó khăn trong việc hiểu luồng điều khiển của một số chương trình đơn giản. Ví dụ hoàn chỉnh của tôi là dưới đây. Lưu ý rằng nó yêu cầu Dataflow library, mà bạn có thể cài đặt từ NuGet.
using System;
using System.Threading.Tasks.Dataflow;
namespace TaskSandbox
{
class Program
{
static void Main(string[] args)
{
BufferBlock<int> bufferBlock = new BufferBlock<int>();
Consume(bufferBlock);
Produce(bufferBlock);
Console.ReadLine();
}
static bool touched;
static void Produce(ITargetBlock<int> target)
{
for (int i = 0; i < 5; i++)
{
Console.Error.WriteLine("Producing " + i);
target.Post(i);
Console.Error.WriteLine("Performing intensive computation");
touched = false;
for (int j = 0; j < 100000000; j++)
;
Console.Error.WriteLine("Finished intensive computation. Touched: " + touched);
}
target.Complete();
}
static async void Consume(ISourceBlock<int> source)
{
while (await source.OutputAvailableAsync())
{
touched = true;
int received = source.Receive();
Console.Error.WriteLine("Received " + received);
}
}
}
}
Output:
Producing 0
Performing intensive computation
Received 0
Finished intensive computation. Touched: True
Producing 1
Performing intensive computation
Received 1
Finished intensive computation. Touched: True
Producing 2
Performing intensive computation
Received 2
Finished intensive computation. Touched: False
Producing 3
Performing intensive computation
Received 3
Finished intensive computation. Touched: False
Producing 4
Performing intensive computation
Received 4
Finished intensive computation. Touched: True
Điều này dường như chỉ ra rằng Consume
được đưa ra kiểm soát trong khi for
vòng lặp đang chạy, như là nhiệm vụ OutputAvailableAsync
hoàn thành:
for (int j = 0; j < 100000000; j++)
;
Đây sẽ là ngạc nhiên trong một mô hình luồng. Nhưng nếu không có chủ đề bổ sung nào có liên quan, làm cách nào để có thể kiểm soát lợi nhuận Produce
ở giữa vòng lặp for
?
@ I4V: Câu trả lời cho câu hỏi đó cho biết rằng "tất cả các hoạt động chặn phải kiểm soát rõ ràng việc kiểm soát bằng mô hình async/await". Nhưng trong câu hỏi của tôi, kiểm soát chuyển từ 'Produce' sang' Consume' mà không có 'Produce' kiểm soát rõ ràng. Đó là phần mà tôi đang bối rối. –
@Matthew Vì đây là một ứng dụng Console không có 'SynchronizationContext', có nghĩa là tất cả các cuộc gọi lại từ các cuộc gọi' await' đi đến 'SynchronizationContext.Default', là nhóm luồng, vì vậy về mặt kỹ thuật, có hai luồng đang chạy đôi khi trong quá trình thực hiện chương trình này. Để ngăn chặn việc tạo ra các chủ đề bổ sung, bạn cần phải tạo bối cảnh đồng bộ tùy chỉnh của riêng bạn và thiết lập đó. Nếu bạn đã làm, bạn sẽ thấy rằng các cuộc gọi 'Recieved' sẽ không được gọi cho đến khi tất cả các sản xuất được thực hiện cụ thể bởi vì bạn * không * kiểm soát năng suất trong khi sản xuất. – Servy
@Servy: Nếu có nhiều chủ đề liên quan, tại sao MSDN cho rằng "Đặc biệt, cách tiếp cận này tốt hơn BackgroundWorker cho các hoạt động IO-bound vì ... bạn không phải bảo vệ chống lại điều kiện chủng tộc"? Tôi đã chỉnh sửa ví dụ của mình để thêm một điều kiện đua đơn giản. –