C# 将异步调用链接在一起-调用永远不会返回

C# 将异步调用链接在一起-调用永远不会返回,c#,.net,async-await,C#,.net,Async Await,我有一个异步调用的层次结构。基本上是这样的: async MyObject MainWorker() { return await Task.Run(SomeSynchronousFunction); } async MyObject InbetweenFunction1() { //do some things return await MainWorker(); } async MyObject InbetweenFunction2() { //do so

我有一个异步调用的层次结构。基本上是这样的:

async MyObject MainWorker()
{
    return await Task.Run(SomeSynchronousFunction);
}

async MyObject InbetweenFunction1()
{
    //do some things
    return await MainWorker();
}

async MyObject InbetweenFunction2()
{
    //do some things 
    return await MainWorker();
}

void ReturnObject TopFunction()
{
    Task<MyObject> return1 = InbetweenFunction1();
    Task<MyObject> return2 = InbetweenFunction2();

    while (!return1.IsComplete || !return2.IsComplete)
         Thread.Sleep(100);

    //access return1.Return and return2.Return values and return from this function
}
async MyObject MainWorker()
{
返回等待任务。运行(SomeSynchronousFunction);
}
异步MyObject中间函数1()
{
//做一些事情
返回等待MainWorker();
}
异步MyObject中间函数2()
{
//做一些事情
返回等待MainWorker();
}
void ReturnObject TopFunction()
{
任务返回1=中间函数1();
任务返回2=中间函数2();
而(!return1.IsComplete | |!return2.IsComplete)
睡眠(100);
//访问return1.Return和return2.返回值并从此函数返回
}
所以我有几个级别的异步调用。顶级方法进行两次异步调用,等待它们完成(通过轮询),然后访问它们的返回值,并对这些值执行操作。问题是,没有一个异步调用完成。函数SomeSynchronousFunction与Task.Run异步调用,最多需要几秒钟,但我等待了30多秒,没有结果


这是我第一次尝试使用新的async/await关键字。我是否做了一些明显错误的事情?

以下是一些可行的代码:

    private async Task<string> DoMainWork()
    {
        await Task.Delay(3000);
        return "MainWorker";
    }

    private async Task<string> InbetweenFunction1()
    {
        // do something
        await Task.Delay(1000);
        return await DoMainWork() + "1";
    }

    private async Task<string> InbetweenFunction2()
    {
        // do something
        await Task.Delay(2000);
        return await DoMainWork() + "2";
    }

    public string TopFunction()
    {
        string return1 = null;
        string return2 = null;

        var taskList = new List<Task>();
        taskList.Add(Task.Run(async () => return1 = await InbetweenFunction1()));
        taskList.Add(Task.Run(async () => return2 = await InbetweenFunction2()));

        Task.WaitAll(taskList.ToArray());

        return return1 + return2;
    }
private async Task DoMainWork()
{
等待任务。延迟(3000);
返回“主要工人”;
}
中间函数1()中的专用异步任务
{
//做点什么
等待任务。延迟(1000);
返回等待域工作()+“1”;
}
中间函数2()中的专用异步任务
{
//做点什么
等待任务。延迟(2000);
返回等待域工作()+“2”;
}
公共字符串TopFunction()
{
字符串return1=null;
字符串return2=null;
var taskList=新列表();
taskList.Add(Task.Run(async()=>return1=wait-InbetweenFunction1());
taskList.Add(Task.Run(async()=>return2=wait-InbetweenFunction2());
Task.WaitAll(taskList.ToArray());
返回1+2;
}

以下是一些可行的代码:

    private async Task<string> DoMainWork()
    {
        await Task.Delay(3000);
        return "MainWorker";
    }

    private async Task<string> InbetweenFunction1()
    {
        // do something
        await Task.Delay(1000);
        return await DoMainWork() + "1";
    }

    private async Task<string> InbetweenFunction2()
    {
        // do something
        await Task.Delay(2000);
        return await DoMainWork() + "2";
    }

    public string TopFunction()
    {
        string return1 = null;
        string return2 = null;

        var taskList = new List<Task>();
        taskList.Add(Task.Run(async () => return1 = await InbetweenFunction1()));
        taskList.Add(Task.Run(async () => return2 = await InbetweenFunction2()));

        Task.WaitAll(taskList.ToArray());

        return return1 + return2;
    }
private async Task DoMainWork()
{
等待任务。延迟(3000);
返回“主要工人”;
}
中间函数1()中的专用异步任务
{
//做点什么
等待任务。延迟(1000);
返回等待域工作()+“1”;
}
中间函数2()中的专用异步任务
{
//做点什么
等待任务。延迟(2000);
返回等待域工作()+“2”;
}
公共字符串TopFunction()
{
字符串return1=null;
字符串return2=null;
var taskList=新列表();
taskList.Add(Task.Run(async()=>return1=wait-InbetweenFunction1());
taskList.Add(Task.Run(async()=>return2=wait-InbetweenFunction2());
Task.WaitAll(taskList.ToArray());
返回1+2;
}

您需要的是一个额外的函数来组合前面的任务

public async Task<string> Combine(Task<string> a, Task<string b){
    var aa = await a;
    var bb = await b;
    return aa + bb; 
}

注意,
真正需要使用阻塞调用的地方之一是应用程序的入口点
主函数
,它不能声明为
异步
,因此不能使用
等待

,您需要的是一个额外的函数来组合前面的任务

public async Task<string> Combine(Task<string> a, Task<string b){
    var aa = await a;
    var bb = await b;
    return aa + bb; 
}
注意,
真正需要使用阻塞调用的地方之一是应用程序的入口点
主函数
,它不能声明为
异步
,因此不能使用
等待

我是不是做错了什么

是的,您正在忙着等待(循环直到条件变为
true
),除非没有其他选项,否则您不应该这样做。这里还有一个更好的选择:使用
Wait()
,或者
Task.WaitAll()

但这样做很可能不会真正使代码正常工作。真正的问题可能是:您处于一个同步上下文中(通常是UI线程或ASP.NET请求上下文),您的
wait
s尝试在该上下文上恢复,但您也在阻止该上下文,等待
任务完成

解决此问题的正确方法是在
TopLevelFunction()
中也使用
wait
。这将要求您将该函数也设置为
async
,这意味着它的调用者现在也必须是
async
,等等。这称为“
async

所有
async
方法都应该是
async Task
方法,但顶级事件处理程序除外,它必须是
async void
。(但是您不应该在其他任何地方使用
async void
方法,因为它们不能
wait
ed。)

这意味着您的功能将变为:

async Task<ReturnObject> TopFunction()
{
    Task<MyObject> return1 = InbetweenFunction1();
    Task<MyObject> return2 = InbetweenFunction2();

    await Task.WhenAll(return1, return2);

    //access await return1 and await return2 values and return from this function
}
异步任务TopFunction()
{
任务返回1=中间函数1();
任务返回2=中间函数2();
等待任务。WhenAll(返回1,返回2);
//访问Wait return1和Wait return2值并从此函数返回
}
我是不是做错了什么

是的,您正在忙着等待(循环直到条件变为
true
),除非没有其他选项,否则您不应该这样做。这里还有一个更好的选择:使用
Wait()
,或者
Task.WaitAll()

但这样做很可能不会真正使代码正常工作。真正的问题可能是:您处于一个同步上下文中(通常是UI线程或ASP.NET请求上下文),您的
wait
s尝试在该上下文上恢复,但您也在阻止该上下文,等待
任务完成

解决此问题的正确方法是在
TopLevelFunction()
中也使用
wait
。这将要求您将该函数也设置为
async
,这意味着它的调用者现在也必须是
async
,等等。这称为“
async

A