Tôi có một số mã thư viện (mạng ổ cắm) cung cấp Task
API dựa trên cơ sở cho các phản hồi đang chờ xử lý cho các yêu cầu, dựa trên TaskCompletionSource<T>
. Tuy nhiên, có một điều khó chịu trong TPL là dường như không thể ngăn chặn sự liên tục đồng bộ. Những gì tôi sẽ thích để có thể làm là một trong hai:
- nói với một
TaskCompletionSource<T>
điều đó là không nên cho phép người gọi đính kèmTaskContinuationOptions.ExecuteSynchronously
, hoặc - đặt kết quả (
SetResult
/TrySetResult
) theo cách chỉ địnhTaskContinuationOptions.ExecuteSynchronously
nên bỏ qua, thay vào đó sử dụng nhóm
Cụ thể, vấn đề tôi gặp phải là dữ liệu đến đang được xử lý bởi một trình đọc chuyên dụng và nếu một người gọi có thể đính kèm với TaskContinuationOptions.ExecuteSynchronously
họ có thể làm ngưng trệ trình đọc (điều này ảnh hưởng nhiều hơn đến họ). Trước đây, tôi đã giải quyết vấn đề này bằng một số hackery phát hiện xem có bất kỳ sự liên tục nào hay không và nếu có thì nó sẽ đẩy việc hoàn thành lên ThreadPool
, tuy nhiên điều này có tác động đáng kể nếu người gọi đã bão hòa hàng đợi công việc của họ, vì quá trình hoàn thành sẽ không được xử lý một cách hợp thời. Nếu họ đang sử dụng Task.Wait()
(hoặc tương tự), về cơ bản họ sẽ tự bế tắc. Tương tự như vậy, đây là lý do tại sao người đọc sử dụng một chuỗi chuyên dụng hơn là sử dụng công nhân.
Vì thế; trước khi tôi thử và cằn nhằn nhóm TPL: tôi có thiếu một lựa chọn không?
Những điểm chính:
- Tôi không muốn người gọi bên ngoài có thể cướp chuỗi của tôi
- Tôi không thể sử dụng
ThreadPool
như một triển khai, vì nó cần hoạt động khi nhóm bão hòa
Ví dụ bên dưới tạo ra sản lượng (đặt hàng có thể thay đổi tùy theo thời gian):
Continuation on: Main thread
Press [return]
Continuation on: Thread pool
Vấn đề là thực tế là một người gọi ngẫu nhiên đã quản lý để có được sự tiếp tục trên "Main thread". Trong mã thực, điều này sẽ làm gián đoạn trình đọc chính; những điều tồi tệ!
Mã:
using System;
using System.Threading;
using System.Threading.Tasks;
static class Program
{
static void Identify()
{
var thread = Thread.CurrentThread;
string name = thread.IsThreadPoolThread
? "Thread pool" : thread.Name;
if (string.IsNullOrEmpty(name))
name = "#" + thread.ManagedThreadId;
Console.WriteLine("Continuation on: " + name);
}
static void Main()
{
Thread.CurrentThread.Name = "Main thread";
var source = new TaskCompletionSource<int>();
var task = source.Task;
task.ContinueWith(delegate {
Identify();
});
task.ContinueWith(delegate {
Identify();
}, TaskContinuationOptions.ExecuteSynchronously);
source.TrySetResult(123);
Console.WriteLine("Press [return]");
Console.ReadLine();
}
}
TaskCompletionSource
hợp với API của riêng mình để ngăn chặn cuộc gọi trực tiếp đếnContinueWith
, vì cả hai đều khôngTaskCompletionSource
và cũngTask
không phù hợp để kế thừa từ chúng.