异步方法相互等待



我正在尝试运行异步程序。
主要有:

using System;
using System.Threading.Tasks;
namespace Test
{
class Program
{
static void Main(string[] args)
{
RunTestsAsync().Wait();
}
private async static Task RunTestsAsync()
{
var a = new SlowString("ab", true);
var b = new SlowString("c", true);
var result1 = a.Equal(b);
var result2 = b.Last(b);
var result3 = b.GreaterThen(a);
result1.Wait();
result2.Wait();
result3.Wait();
Console.WriteLine();
Console.WriteLine("Results: {0},   {1},   {2}", result1.Result, result2.Result, result3.Result);
Console.WriteLine();
}
}
}

这是第二个文件:

using System;
using System.Threading.Tasks;
namespace Test
{
class SlowString
{
private readonly string str;
private readonly bool msg;
private readonly int delay;
public SlowString(string str, bool msg = false, int delay = 30)
{
this.str = str;
this.msg = msg;
this.delay = delay;
}
public async Task<bool> Equal(SlowString other)
{
if(msg) Console.WriteLine("SlowString Equals Started");
Task.Delay(delay).Wait();
bool result = await Task.Run(() => { return str.Equals(other.str); });
if (msg) Console.WriteLine("SlowString Equals Ended");
return result;
}
public async Task<bool> GreaterThen(SlowString other)
{
if (msg) Console.WriteLine("SlowString GreaterThen Started");
Task.Delay(delay).Wait();
bool result = await Task.Run(() => { return str.CompareTo(other.str) > 0 ? true : false; });
if (msg) Console.WriteLine("SlowString GreaterThen Ended");
return result;
}
public async Task<SlowString> Last(SlowString other)
{
if (msg) Console.WriteLine("SlowString Last Started");
Task.Delay(delay).Wait();
SlowString result = await Task.Run(() => { return str.CompareTo(other.str) > 0 ? this : other; });
if (msg) Console.WriteLine("SlowString Last Ended");
return result;
}
public override string ToString()
{
return str;
}
}
}

问题是我的程序总是等待先前的计算完成,所以我得到:

慢字符串等于已开始 慢字符串等于结束 慢字符串上次开始 慢字符串上次结束 慢字符串更大然后

开始
慢字符串
更大然后结束



即使有更大的延迟,比如 3000 毫秒的程序 stil 会等到 result1 被计算出来,
然后转到 result2 并计算它,然后才走得更远。

我想我真的什么都试过了。请给我一些线索。

您正在调用.Wait(),顾名思义,它会等到任务完成。它会阻止执行。所以第一件事永远不要打电话给.Wait().Result或任何类似的东西。始终awaitasync方法一起使用。

但是,简单地将.Wait()更改为await是行不通的,因为您正在尝试并行运行任务。在这种情况下,您的例程应该看起来更像:

var result1 = Task.Run(() => a.Equal(b));
var result2 = Task.Run(() => b.Last(b));
var result3 = Task.Run(() => b.GreaterThen(a));
await Task.WhenAll(new [] {result1, result2, result3});

关于其他说明:

Task.Delay(delay).Wait();

也应该是

await Task.Delay(delay);

还有这样的台词:

bool result = await Task.Run(() => { return str.CompareTo(other.str) > 0 ? true : false; });

除了应用开销之外,不要执行任何其他操作:您正在线程池上调用一个新任务并立即等待结果。它是同步包裹在人工异步性中的。这:

bool result = str.CompareTo(other.str) > 0 ? true : false;

可能会运行得更快,因为没有开销。

您的Main方法应该是:

static async Task Main(string[] args)
{
await RunTestsAsync();
}

最新更新