停止冒泡异步等待任务到调用者而不会出现死锁

时间:2018-01-05 15:35:38

标签: c# asynchronous async-await task

我有一个问题,我有一个使用异步函数的库,GetParametersByPathAsync(在此定义:https://github.com/aws/aws-sdk-net/blob/master/sdk/src/Services/SimpleSystemsManagement/Generated/_mobile/AmazonSimpleSystemsManagementClient.cs#L2718

我有一个定义为

的库函数
Task<Dictionary<string,string>> GetAllParameters(string region)
{
    var pars = DoParameterGatheringWork(reigion);
    ...(do some more work)
    return dict;
}

调用另一种方法

async Task<Dictionary<string,string>> DoParameterGatheringWork(string region)
{
    ...
    var response = await GetParametersByPathAsync(requestObj);
    ... (process the response)
    return parameterDict;
}

等待GetParametersByPathAsync并收集内容。

这是一个问题,因为我的服务必须从静态构造函数调用GetAllParameters并初始化参数Dictionary<string,string> MyParameters { get; }

我想在库中的某个位置阻止任务冒泡,因此它只能公开Dictionary<string,string> GetAllParameters(string region),而不是任务版本。 (我完全没问题就变得同步了。)

我认为我不应该仅仅执行Task.Wait()Task.Result,因为这会导致死锁。

也许这不是最好的方法,但我不确定如何从这里继续。

任何想法都将不胜感激!

编辑:

这是我想要的构造函数代码:

public class MyConfiguration
{
    static MyConfiguration()
    {
        ...
        Parameters = ServiceConfiguration.GetAllParameters(); // (library call)
    }
    public static Dictionary<string, string> Parameters { get; }
}

并且客户端只能通过MyConfiguration.Parameters["IAMAPARAMETER"]

在任何地方使用此功能

1 个答案:

答案 0 :(得分:0)

评论后:在这个答案的最后:如何从非异步方法调用异步方法

显然DoParameterGatheringWork是一个通常需要忙着等待另一个进程的函数,比如数据库,文件或来自互联网的一些信息。

该函数的设计者认为,如果您的线程暂时等待此删除操作的结果,那将是浪费时间。因此,他决定将其设置为异步,因此调用者可以执行其他操作,而另一个进程将处理请求。

您认为这意味着这意味着所有调用者也应该是异步的,并且构造函数不能是异步的。

如果您希望受益于async-await的优势(意味着您的调用者可以继续处理而不是空闲等待,请使您的构造函数更轻,并让一些Create函数执行您通常在构造函数中执行的异步作业。强制每个想要你的类的对象使用这个异步创建函数的人。

public class MyConfiguration
{
    // Static async Create function, does everything you'd normally do in the constructor:
    public static async Task<MyConfiguration> CreateAsync()
    {
        Dictionary<string,string> allParameters = await ServiceConfiguration.GetAllParameters(...);
        MyConfiguration createdConfiguration = new MyConfiguration(allParameters);
        return createdConfiguration;
     }

     // make sure that no one except CreateAsync can call the constructor:
     private MyConfiguration(Dictionary<string,string> allParameters)
     {
          parameters = allParameters;
     }
}

你所做的就是让构造函数尽可能轻量级并完成所有困难的工作,包括在CreateAsync函数中等待。

<强>用法:

以下将导致编译器错误,因此您在开始运行之前就知道了该问题:

MyConfiguration config = new MyConfiguration(...);

正确使用:

async Task<...> DoSomethingAsync(...)
{
     ...
     // I need a configuration:
     MyConfiguration config = await MyConfiguration.Create();
     // from here you can use the fully initialized MyConfiguration object:
     config.DoSomethingElse();
     ...
}

简单的纪念活动

添加:如何从非异步函数调用异步方法

要从非异步方法调用异步函数,请使用Task.Run启动异步函数,Task.Wait等待异步函数完成,Task.Result获取返回异步函数的值。

static void Main(string[] args)
{
    // call an async function:
    var asyncTask = Task.Run( () => MyAsyncFunction(...));

    // if desired: do other things
    DoSomethingElse();

    // now you need the result of the async function
    asyncTask.Wait();
    var returnValue = asyncTask.Result;
    Process(returnvalue);
}