简体   繁体   English

需要执行上下文来组合异步和TPL代码

[英]Need an execution context for combination of async and TPL code

I'm looking for an execution context which plays nicely with async/await and with the TPL at the same time in the following way (expected behavior): 我正在寻找一种执行上下文,它可以通过以下方式(预期行为)与async/await和TPL同时很好地发挥作用:

async Task<string> ReadContext(string slot)
{
    // Perform some async code
    ...
    return Context.Read(slot);
}

(1) Playing nicely with async/await (1)与async/await玩得很好

Context.Store("slot", "value");
await DoSomeAsync();
Assert.AreEqual("value", Context.Read("slot"));

Context.Store("slot", "value");
var value = await ReadContext("slot");
Assert.AreEqual("value", value);

(2) Playing nicely with Task.Run() (2)与Task.Run()很好

Context.Store("slot", "value");
var task = Task.Run(() => ReadContext("slot"));
Assert.IsNull(task.Result);

(3) Playing nicely with an awaited Task (3)与期待的Task相处Task

Context.Store("slot", "value");
var value = await Task.Run(() => ReadContext("slot"));
Assert.AreEqual("value", value);

(3) is not essential but would be nice. (3)不是必需的,但会很好。 I use CallContext now but it fails at (2) as the values stored in it are accessible even in manually ran tasks, even in those ran using Task.Factory.StartNew(..., LongRunning) which should enforce running the task on a separate thread. 我现在使用CallContext但是它失败于(2),因为即使在手动运行的任务中也可以访问其中存储的值,即使在使用Task.Factory.StartNew(..., LongRunning)运行的任务中,也可以强制在单独的线程。

Is there any way to accomplish that? 有什么办法可以做到这一点?

Your real question is in your comment: 您的真正问题在您的评论中:

I need a place to store NHibernate sessions in ASP.NET application. 我需要在ASP.NET应用程序中存储NHibernate会话的地方。 HttpContext works fine (and respects async/await) if I'm inside a request context, but it is unavailable once I jump into manually ran tasks. 如果我位于请求上下文中,则HttpContext可以很好地工作(并尊重异步/等待),但是一旦我跳入手动运行的任务,它就不可用。

First off, you should be avoiding "manually run tasks" in an ASP.NET application at all; 首先,您应该完全避免ASP.NET应用程序中的“手动运行任务”。 I have a blog post on the subject. 我有一篇关于该主题的博客文章

Secondly, storing things in HttpContext.Items is sort of a hack. 其次,将内容存储在HttpContext.Items是一种hack。 It can be useful in a handful of situations, but IMO managing NHibernate sessions is something that should be designed properly into your application. 在少数情况下它可能很有用,但是IMO管理NHibernate会话应该在您的应用程序中进行适当设计。 That means you should be passing around the session (or a service providing access to the session) either in your method calls or injected into each type that needs it. 这意味着您应该在方法调用中传递会话(或提供对会话的访问的服务),或者将其传递给需要它的每种类型。

So, I really think that a "context" like you're looking for is a wrong solution. 因此,我真的认为像您正在寻找的“上下文”是错误的解决方案。 Even if it were possible, which it is not. 即使有可能,但事实并非如此。

As @Noseratio noted, requirements (2) and (3) cannot both be met. 如@Noseratio所述,要求(2)和(3)不能同时满足。 Either the code executing in the Task.Run has access or it does not; Task.Run执行的代码是否可以访问; it can't be both. 不能两者兼有。

As you've discovered, requirements (1) and (3) can be met by the logical call context (note to Googlers: this only works under .NET 4.5 and only if you store immutable data; details on my blog ). 如您所知,逻辑调用上下文可以满足要求(1)和(3)(请注意Google员工:这在.NET 4.5下有效,并且仅当您存储不可变数据时才可用; 有关我的博客的详细信息)。

There is no easy way to satisfy (1) and (2) unless you manually remove the data ( FreeNamedDataSlot ) at the beginning of the code in Task.Run . 除非您在Task.Run中的代码开头手动删除数据( FreeNamedDataSlot ),否则没有简单的方法来满足(1)和(2)。 I think there may be another solution but it would require custom awaitables at every await, which is completely cumbersome, brittle, and unmaintainable. 我认为可能还有另一种解决方案,但是每次等待都需要自定义的等待项,这完全麻烦,脆弱且无法维护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM