Tùy thuộc vào việc tôi đang sử dụng mã dựa trên mã async/await hay mã TPL, tôi nhận được hai hành vi khác nhau liên quan đến việc dọn dẹp hợp lý CallContext
.Làm sạch CallContext trong TPL
tôi có thể thiết lập và rõ ràng logic CallContext
chính xác như tôi mong đợi nếu tôi sử dụng async sau/chờ đợi mã:
class Program
{
static async Task DoSomething()
{
CallContext.LogicalSetData("hello", "world");
await Task.Run(() =>
Debug.WriteLine(new
{
Place = "Task.Run",
Id = Thread.CurrentThread.ManagedThreadId,
Msg = CallContext.LogicalGetData("hello")
}))
.ContinueWith((t) =>
CallContext.FreeNamedDataSlot("hello")
);
return;
}
static void Main(string[] args)
{
DoSomething().Wait();
Debug.WriteLine(new
{
Place = "Main",
Id = Thread.CurrentThread.ManagedThreadId,
Msg = CallContext.LogicalGetData("hello")
});
}
}
Ở trên kết quả đầu ra như sau:
{Nơi = Task.Run , Id = 9, Msg = thế giới}
{Nơi = Main, Id = 8, Msg =}
Thông báo các 012.cho biết rằng CallContext
trên chủ đề chính đã được giải phóng và trống.
Nhưng khi tôi chuyển sang tinh khiết TPL mã/TAP tôi không thể đạt được hiệu quả tương tự ...
class Program
{
static Task DoSomething()
{
CallContext.LogicalSetData("hello", "world");
var result = Task.Run(() =>
Debug.WriteLine(new
{
Place = "Task.Run",
Id = Thread.CurrentThread.ManagedThreadId,
Msg = CallContext.LogicalGetData("hello")
}))
.ContinueWith((t) =>
CallContext.FreeNamedDataSlot("hello")
);
return result;
}
static void Main(string[] args)
{
DoSomething().Wait();
Debug.WriteLine(new
{
Place = "Main",
Id = Thread.CurrentThread.ManagedThreadId,
Msg = CallContext.LogicalGetData("hello")
});
}
}
Các kết quả trên như sau:
{Nơi = Task.Run , Id = 10, Msg = thế giới}
{Nơi = Main, Id = 9, Msg = thế giới}
có bất cứ điều gì tôi có thể làm gì để ép buộc TPL để "tự do" sự hợp lý CallContext
giống như mã async/await hiện không?
Tôi không quan tâm đến các lựa chọn thay thế cho CallContext
.
Tôi hy vọng sẽ nhận được mã TPL/TAP ở trên được khắc phục để tôi có thể sử dụng nó trong các dự án nhắm mục tiêu khuôn khổ .net 4.0. Nếu điều đó là không thể trong .net 4.0, tôi vẫn tò mò nếu nó có thể được thực hiện trong .net 4.5.
trong phiên bản TPL của bạn, là có một nguy cơ rằng CallContext logic sẽ được trả tự do trước khi Task.Factory.StartNew đã có một cơ hội để Capture nó? Tôi cũng cần phải chắc chắn rằng tất cả các tiếp tục (nếu có) từ Task.Factory.StartNew thực sự có CallContext, ngay cả khi nó được "giải phóng" bởi chủ đề chính. –
@BrentArias bạn có thể kiểm tra nó bằng Thread.Sleep (tôi đã làm). Task.Factory.StartNew cũng như Task.Run capture (copy) bối cảnh và lưu trữ nó trên Task nên bạn không cần phải lo lắng về nó. Bạn có thêm thông tin về nó tại đây: http://blogs.msdn.com/b/pfxteam/archive/2012/06/15/executioncontext-vs-synchronizationcontext.aspx – i3arnon
@BrentArias * "khi bạn sử dụng Task.Run, Call to Run bắt ExecutionContext từ thread đang gọi, lưu trữ cá thể ExecutionContext đó vào đối tượng Task.Khi đại biểu được cung cấp cho Task.Run sau đó được gọi như là một phần của thực thi của Task, nó được thực hiện thông qua ExecutionContext.Run bằng cách sử dụng ngữ cảnh được lưu trữ. Điều này đúng với Task.Run, cho ThreadPool.QueueUserWorkItem, cho Delegate.BeginInvoke, cho Stream.BeginRead, cho DispatcherSynchronizationContext.Post và cho bất kỳ API async nào khác mà bạn có thể nghĩ đến. "* – i3arnon