C# 异步/等待继续

C# 异步/等待继续,c#,asynchronous,async-await,C#,Asynchronous,Async Await,在下面的代码中,我需要执行三个Get。。。方法并行。当一个男人。。。方法完成我需要立即调用Save。。。方法。注意保存。。。将对象作为参数。 所有Get和Save方法必须在DoStuffAsync返回之前完成 我想我需要在Get上继续。。。方法,但我不知道如何构建它 protected async void DoStuffAsync() { SomeThing thing = new SomeThing { ID = 5 }; SomeRepository rep = new S

在下面的代码中,我需要执行三个Get。。。方法并行。当一个男人。。。方法完成我需要立即调用Save。。。方法。注意保存。。。将对象作为参数。 所有Get和Save方法必须在DoStuffAsync返回之前完成

我想我需要在Get上继续。。。方法,但我不知道如何构建它

protected async void DoStuffAsync()
{
    SomeThing thing = new SomeThing { ID = 5 };
    SomeRepository rep = new SomeRepository();

    // We need to run all three Get... methods in parallel
    // As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method .

    var getRed = rep.GetRedAsync().ContinueWith<Task<string>>(async x => { thing.Color1 = x.Result; await rep.SaveRedAsync(thing); return x; }); // does not compile
    var getBlue = rep.GetBlueAsync();
    var getGreen = rep.GetGreenAsync();

    string red = await getRed.Result; // this is not good because getBlue may finish before getRed.  We want dont want to wait on getRed before calling SaveBlue
    await rep.SaveRedAsync(thing);
    var b = await getBlue;  
    var c = await getGreen;

    // thing must be fully initialized before DoStuffAsync returns

    }


public class SomeThing
{
    public int ID { get; set; }
    public string Color1 { get; set; }
    public string Color2 { get; set; }
    public string Color3 { get; set; }
}

public class SomeRepository
{
    public async Task<string> GetRedAsync()
    {
        return await Task.Run(() => "red");
    }

    public async Task<string> GetBlueAsync()
    {
        return await Task.Run(() => "blue");
    }

    public async Task<string> GetGreenAsync()
    {
        return await Task.Run(() => "green");
    }

    public async Task SaveRedAsync(SomeThing thing)
    {
        // We need thing.ID here as well as other properties
        await Task.Delay(1);
    }

    public async Task SaveBlueAsync(SomeThing thing)
    {
        await Task.Delay(1);
    }

    public async Task SaveGreenAsync(SomeThing thing)
    {
        await Task.Delay(1);
    }
}
受保护的异步void dostufasync()
{
某物=新事物{ID=5};
SomeRepository rep=新建SomeRepository();
//我们需要并行运行所有三个Get…方法
//一旦Get…方法完成,我们需要将结果保存到thing的正确属性,并调用save…方法。
var getRed=rep.GetRedAsync().ContinueWith(async x=>{thing.Color1=x.Result;wait rep.SaveRedAsync(thing);return x;});//不编译
var getBlue=rep.GetBlueAsync();
var getGreen=rep.GetGreenAsync();
string red=wait getRed.Result;//这不好,因为getBlue可能在getRed之前完成。我们不想在调用SaveBlue之前等待getRed
等待rep.SaveRedAsync(东西);
var b=等待getBlue;
var c=等待绿色;
//在DoStuffAsync返回之前,必须完全初始化对象
}
公开课
{
公共int ID{get;set;}
公共字符串Color1{get;set;}
公共字符串Color2{get;set;}
公共字符串Color3{get;set;}
}
公共类存储库
{
公共异步任务GetRedAsync()
{
返回等待任务。运行(()=>“红色”);
}
公共异步任务GetBlueAsync()
{
返回等待任务。运行(()=>“蓝色”);
}
公共异步任务GetGreenAsync()
{
返回等待任务。运行(()=>“绿色”);
}
公共异步任务SaveRedAsync(某物)
{
//我们需要thing.ID以及其他属性
等待任务。延迟(1);
}
公共异步任务SaveBlueAsync(SomeThing)
{
等待任务。延迟(1);
}
公共异步任务SaveGreenAsync(某物)
{
等待任务。延迟(1);
}
}
好吧,您可以显式地使用
ContinueWith
——或者您可以将每个“获取并保存”中断为单独的异步方法或异步lambda。例如:

async Task GetAndSaveRedAsync(SomeThing thing, SomeRepository rep)
{
    var red = await rep.GetRedAsync();
    thing.Red = red;
    await SaveRedAsync(red);
    // Return red if you want (change the return type to Task<string>)
}

// Ditto for the others

您可以尝试并行框架:

using System.Threading;

using System.Threading.Tasks;

Func<Task<string>>[] functions = { rep.GetRedAsync, rep.GetBlueAsync, rep.GetGreenAsync }; 
Var[] GetArray = new Var[functions.Length]
int i=0;
Parallel.ForEach (var function in functions)  
{  
             GetArray[i++]=function();

}  
使用系统线程;
使用System.Threading.Tasks;
Func[]函数={rep.GetRedAsync,rep.GetBlueAsync,rep.GetGreenAsync};
Var[]GetArray=new Var[functions.Length]
int i=0;
Parallel.ForEach(函数中的var函数)
{  
GetArray[i++]=function();
}  

注意:要求
.Net 4
我不会将
继续与
等待
混合,而是直接使用
异步
lambda:

protected async Task  DoStuffAsync()
{
    SomeThing thing = new SomeThing { ID = 5 };
    SomeRepository rep = new SomeRepository();

    // We need to run all three Get... methods in parallel
    // As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method .

    Func<Task<X>> getRedFunc = async() =>
    {
        var result = await rep.GetRedAsync();
        thing.Color1 = result;
        await rep.SaveRedAsync(thing);
        return result;
    };

    var getRed = getRedFunc();

    var getBlue = rep.GetBlueAsync();
    var getGreen = rep.GetGreenAsync();

    await Task.WhenAll(getRed, getBlue, getGreen);
}
受保护的异步任务DoStuffAsync()
{
某物=新事物{ID=5};
SomeRepository rep=新建SomeRepository();
//我们需要并行运行所有三个Get…方法
//一旦Get…方法完成,我们需要将结果保存到thing的正确属性,并调用save…方法。
Func getRedFunc=async()=>
{
var result=await rep.GetRedAsync();
thing.Color1=结果;
等待rep.SaveRedAsync(东西);
返回结果;
};
var getRed=getRedFunc();
var getBlue=rep.GetBlueAsync();
var getGreen=rep.GetGreenAsync();
等待任务。WhenAll(红色、蓝色、绿色);
}

另外,除了事件处理程序之外,不要对任何东西使用
async void
方法。您将无法观察此类方法的完成情况,也无法处理其中可能引发的异常。

如果您有可以运行但无法编译的代码,请包含编译错误。为什么有人编写异步任务时会等待另一个任务。为什么不写一个任务,在这个调用中使用“普通”而不是异步方法呢。由于您的任务已经在不同的线程上运行,synchc方法不会阻止UI。但是在一个任务中调用一个任务并等待它,这不是不必要的开销吗?@RandRandom:是什么让你认为任何东西都在不同的线程上运行?是的,您可以使用
任务。运行
并为此指定一个线程,但是为什么您要创建比您需要的更多的线程?所以我猜您是说任务不会在不同的线程上运行?我认为这是您编写任务以便它可以在不同线程中异步运行的唯一原因。@RandRandom:不一定,不一定。它可能会这样做,但它当然不必这样做。考虑一个WiFrm应用程序,包含“代码>异步空格HandleButtonClick(…){按钮”。文本=“等待”;等待任务。延迟(1000);按钮。文本=“等待”;}<代码> -没有额外的线程参与其中。关于async,可能值得你再次阅读:)@user579342:没有“线程中的线程”这样的东西,我给出的代码根本不会启动任何新线程。我没有回避Randrandy的问题,而是质疑它的基本假设。你似乎认为TAP是关于并行性的——不是,而是关于异步,这是不同的。你有没有理由说“我不会把ContinueWith和await混为一谈?”@NStuke,不一定按这个顺序,但是:1)代码结构和可读性;2) 考虑当前
SynchronizationContext
TaskScheduler
的方式不同,3)处理和传播异常的方式不同;4) 延续lambda运行方式的差异(人们往往忘记同步执行
);5) 我肯定我错过了其他一些东西,但这应该足够了:)
protected async Task  DoStuffAsync()
{
    SomeThing thing = new SomeThing { ID = 5 };
    SomeRepository rep = new SomeRepository();

    // We need to run all three Get... methods in parallel
    // As soon as a Get... method completes we need to save the result to the correct property on thing and call the Save... method .

    Func<Task<X>> getRedFunc = async() =>
    {
        var result = await rep.GetRedAsync();
        thing.Color1 = result;
        await rep.SaveRedAsync(thing);
        return result;
    };

    var getRed = getRedFunc();

    var getBlue = rep.GetBlueAsync();
    var getGreen = rep.GetGreenAsync();

    await Task.WhenAll(getRed, getBlue, getGreen);
}