如何在C#中跨异步等待模型维护线程上下文?

时间:2014-05-09 01:28:16

标签: c# async-await threadstatic

每次await完成“选项”时,是否正在使用ThreadStatic并设置上下文?还有另一种方式吗?

public async void Test()
{
    // This is in Thread 1
    Foo foo = new Foo();
    Context.context = "context1"; // This is ThreadStatic
    string result = await foo.CallAsynx();

    // This is most likely Thread 2
    Context.context = "context1";   // This might be a different thread and so resetting context    
}

如果我不想使用ThreadStatic,现在有另一种方法吗?

2 个答案:

答案 0 :(得分:15)

ThreadStaticThreadLocal<T>,主题数据广告位和CallContext.GetData / CallContext.SetDataasync不兼容,因为它们是特定于线程的。< / p>

最好的选择是:

  1. 将其作为@PauloMorgado建议的参数传递。等效地,您可以将其设置为对象的字段成员(它通过this隐式地作为参数传递);或者你可以让你的lambdas捕获变量(在下面,编译器将通过this隐式地将它作为参数传递。)
  2. 使用HttpContext.Items(如果您使用的是ASP.NET 4.5)。
  3. 使用CallContext.LogicalGetData / CallContext.LogicalSetData作为@Noseratio建议。您只能在逻辑线程上下文中存储不可变数据;它仅适用于.NET 4.5,并不适用于所有平台(例如,Win8)。
  4. 通过安装&#34;主循环&#34;强制所有async个延续回到同一个线程。对于该线程,例如AsyncContext from my AsyncEx library

答案 1 :(得分:1)

几年后,如果有人有相同的问题并找到了这个线索...

有一个名为

的新功能
from requests.auth import HTTPBasicAuth
import requests
import json
import urllib3

urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

def countries():
    data = requests.get("https://localhost/api/netim/v1/countries/", verify=False, auth=HTTPBasicAuth("admin", "admin"))
    rep = data.json()
    a = []
    for elem in rep['items']:
        a.extend([elem.get("id","")])
    print(a)
    return a
def regions():
    ids = []
    for c in countries():
        url = requests.get("https://localhost/api/netim/v1/countries/{}/regions".format(c), verify=False, auth=HTTPBasicAuth("admin", "admin"))
        response = url.json()
        for cid in response['items']:
            ids.extend([cid.get("id","")])
        data = []
        for r in ids:
            url = requests.get("https://localhost/api/netim/v1/regions/{}/cities".format(r), verify=False, auth=HTTPBasicAuth("admin", "admin"))
            response = url.json()
            data.extend([{"name":r.get("name",""),"id":r.get("id", "")} for r in response['items']])
        print(json.dumps(data, indent=4))
    return data
regions()

print(regions())

https://docs.microsoft.com/en-us/dotnet/api/system.threading.asynclocal-1?view=netcore-3.1

这适用于“异步/等待”,也适用于:

  • Task.Run(...)
  • Dispatcher.BeginInvoke(...)
  • 新线程(...)。启动()

我只是用以下代码测试这三个:

AsyncLocal<T>

输出:

P:工作2-2

P:工作1-1

P2:工作2-2

P:工作2-2

P2:工作1-1

P:工作1-1

P2:工作2-2

T:工作2-2

P2:工作1-1

T:工作1-1