C# 从异步任务方法返回“normal”变量

C# 从异步任务方法返回“normal”变量,c#,asynchronous,async-await,task,C#,Asynchronous,Async Await,Task,在我的一种方法中,我想创建一辆如下所示的汽车: public string[] CreateCar() { string[] wheels = CreateWheels(); // Also add motor and other stuff here string[] motor = ...; return new string[][]{ wheels, motor, ... }; } 这里创建了四个轮子,它们彼此不依赖。 因此,我可以将它们放在多个任务中

在我的一种方法中,我想创建一辆如下所示的汽车:

public string[] CreateCar()
{
    string[] wheels = CreateWheels();

    // Also add motor and other stuff here
    string[] motor = ...;

    return new string[][]{ wheels, motor, ... };
}
这里创建了四个轮子,它们彼此不依赖。 因此,我可以将它们放在多个任务中,并且可以并行处理。在我的实际代码中,这在并行for循环中是不可能的

public string[] CreateWheels()
{
    Task FL = Task.Run(() => CreateWheel("front left");
    Task FR = Task.Run(() => CreateWheel("front right");
    Task BL = Task.Run(() => CreateWheel("back left");
    Task BR = Task.Run(() => CreateWheel("back right");

    // Here I really want to wait for all wheels to be created!
    // STOP THE PROCESS HERE UNTIL ALL WHEELS ARE COMPLETED!!!
    string[] wheels = await Wask.WhenAll(FL, FR, BL, BR); 

    return wheels;
}
一个轮子是这样创建的:

public string CreateWheel(string position)
{
    // Here a wheel is created, whatever it takes :)
    return "wheel " + position;
}
我现在的问题是: 为了编译代码,它迫使我将CreateWheels标记为异步方法。否则我不能用等待。 ⇒ 但这迫使我将其返回值更改为任务 ⇒ 但是,我需要在CreateCar方法中的CreateWheels前面放置一个wait,以便获取字符串数组,而不是任务本身

⇒ 然后循环重复,因为现在CreateWheels中有一个等待,迫使我使其异步。。。等等,等等

这个循环一直重复,直到最后出现一个void方法,在这里您不需要使用wait来提取返回值


如果我只想等待所有轮子在标记点完成,那么这个循环的出路是什么?

如果你想同步,那么Task.WaitAll可能会有帮助,即

Task.WaitAllFL、FR、BL、BR; 变量轮=新[]{FL.Result,FR.Result,BL.Result,BR.Result}; 如果希望这是异步的,则需要将方法设为async[Value]任务,并在整个过程中传播异步性。异步是粘着的——它粘着一切;但是:

字符串[]轮=等待任务。当所有FL、FR、BL、BR;
然而,坦率地说,我怀疑在这种情况下两者都没有必要;并行性并不便宜,而且可能会增加比它在这里所值的更多的开销。

如果您希望这是同步的,那么Task.WaitAll可能会有所帮助,即

string[] wheels = Wask.WhenAll(FL, FR, BL, BR).Result;
Task.WaitAllFL、FR、BL、BR; 变量轮=新[]{FL.Result,FR.Result,BL.Result,BR.Result}; 如果希望这是异步的,则需要将方法设为async[Value]任务,并在整个过程中传播异步性。异步是粘着的——它粘着一切;但是:

字符串[]轮=等待任务。当所有FL、FR、BL、BR; 然而,坦率地说,我怀疑在这种情况下两者都没有必要;并行性并不便宜,而且可能会增加比它在这里所值的更多的开销

string[] wheels = Wask.WhenAll(FL, FR, BL, BR).Result;
我会做你想做的。这些单独的任务仍将并行运行

缺点是调用线程将阻塞,直到这些任务全部解决

我会做你想做的。这些单独的任务仍将并行运行


缺点是调用线程将阻塞,直到这些任务全部解决。

可以通过使用Task.Run启动多个任务来实现并行性,但是为什么不使用专门的工具(如库)来完成任务呢?您不仅可以避免使用该属性,该属性与wait结合使用时会导致严重的死锁,而且还可以定义最大并行度作为奖励:

var wheelNames = new[] { "front left", "front right", "back left", "back right" };
string[] wheels = wheelNames
    .AsParallel()
    .AsOrdered()
    .WithDegreeOfParallelism(4)
    .Select(x => CreateWheel(x))
    .ToArray();

可以通过使用Task.Run启动多个任务来实现并行性,但是为什么不使用专门的工具来完成任务,比如库呢?您不仅可以避免使用该属性,该属性与wait结合使用时会导致严重的死锁,而且还可以定义最大并行度作为奖励:

var wheelNames = new[] { "front left", "front right", "back left", "back right" };
string[] wheels = wheelNames
    .AsParallel()
    .AsOrdered()
    .WithDegreeOfParallelism(4)
    .Select(x => CreateWheel(x))
    .ToArray();

除非CreateCar是一个要求特殊性的方法,否则我不明白为什么要使用Task.Run来执行它;应该work@UnholySheep:哦,太好了!那么,所有的任务都是并行执行的吗?您不想编写代码有什么原因吗?正如其他人提到的,异步在某种程度上具有传染性。根据这段代码嵌套的深度,交换所有内容可能会有点痛苦,但这比尝试调试任务IMO上使用.Result可能导致的任何死锁条件更痛苦。除非CreateCar是一种特殊要求的方法,否则我不明白为什么要使用task.Run来执行它。string[]轮子=任务时FL、FR、BL、BR结果;应该work@UnholySheep:哦,太好了!那么,所有的任务都是并行执行的吗?您不想编写代码有什么原因吗?正如其他人提到的,异步在某种程度上具有传染性。根据这段代码嵌套的深度不同,交换所有内容可能会有点痛苦,但这比尝试调试任何死锁条件更痛苦。任务结果IMO。非常感谢!如果下面的代码取决于CreateWheels的结果,那么无论如何都无法避免调用线程为block?而不是使用WhenAll.Result为什么不使用WaitAll,因为它是WhenAll的同步对应项?@TylerHundley也可以。WhenAll将一次性展开所有任务,并留给您一个正常的字符串数组。如果你把我的答案和马克的相比,你会发现即使打电话给WaitAll,他仍然必须这么做
处理多项任务并多次调用结果。但这只是偏好。很好,谢谢!如果下面的代码取决于CreateWheels的结果,那么无论如何都无法避免调用线程为block?而不是使用WhenAll.Result为什么不使用WaitAll,因为它是WhenAll的同步对应项?@TylerHundley也可以。WhenAll将一次性展开所有任务,并留给您一个正常的字符串数组。如果你把我的答案和Marc的相比,你会发现即使打了WaitAll,他仍然要处理好几项任务,并多次打电话给Result。但这只是偏好。