C#异步等待怪异行为
我是C#的新手,现在我想了解异步/等待特征。所以,我创建了小沙盒应用程序:C#异步等待怪异行为
namespace sandbox
{
public class Test
{
public async Task<string> GetItemsAsync()
{
var a = await Task1();
var b = await Task2();
var c = await Task3();
return a + b + c;
}
public string GetItems()
{
return _T1() + _T2() + _T3();
}
private readonly int cycles = 100000000;
private async Task<string> Task1()
{
return await Task.Factory.StartNew(_T1);
}
private async Task<string> Task2()
{
return await Task.Factory.StartNew(_T2);
}
private async Task<string> Task3()
{
return await Task.Factory.StartNew(_T3);
}
// long running operation
private string _T1()
{
for (int i = 0; i < cycles; i++) ;
for (int i = 0; i < cycles; i++) ;
return "One";
}
// long running operation
private string _T2()
{
for (int i = 0; i < cycles; i++) ;
for (int i = 0; i < cycles; i++) ;
return "Two";
}
// long running operation
private string _T3()
{
for (int i = 0; i < cycles; i++) ;
for (int i = 0; i < cycles; i++) ;
return "Three";
}
}
class Program
{
static void Main(string[] args)
{
var t = new Test();
Console.WriteLine("Async");
Stopwatch sw = new Stopwatch();
sw.Start();
var result = t.GetItemsAsync();
Console.WriteLine(result.Result);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.WriteLine("Sync");
sw.Restart();
var strResult = t.GetItems();
Console.WriteLine(strResult);
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Console.ReadLine();
}
}
}
但结果是怪异:
Async
OneTwoThree
1754
Sync
OneTwoThree
1506
异步方法运行时间比类似的同步之一。对我来说,它看起来像异步方法同步运行,但我不知道为什么。
正因为如此:
var a = await Task1();
var b = await Task2();
var c = await Task3();
之前,你甚至开始Task2
你已经等了Task1
完成。所以你不是在平行运行它们,而是依次运行它们。
如果要启动所有3个任务,然后等待它们完成,你就必须改变这种方法是:
public async Task<string> GetItemsAsync()
{
var t1 = Task1();
var t2 = Task2();
var t3 = Task3();
var a = await t1;
var b = await t2;
var c = await t3;
return a + b + c;
}
或者只是最后一部分:
return (await t1) + (await t2) + (await t3);
另外,这个代码是一个反模式:
private async Task<string> Task3()
{
return await Task.Factory.StartNew(_T3);
}
你不需要async/await
这里因为... e 在您的子任务返回后,您无法继续使用此方法。
而不是简单地改写这个方法(和它的兄弟姐妹),以这样的:
private Task<string> Task3()
{
return Task.Factory.StartNew(_T3);
}
“未开始任务”是什么意思?这是3种方法的责任,明确地开始新的任务。开始任务不是我的责任*如果该任务返回给我*。这是*的责任,无论它是什么返回*。无论如何,这些任务显然开始,'Task.Factory.StartNew'。 –
道歉我误解他们的代码,并没有注意到任务方法内的开始 – MikeT
op *可以* elide'async' /'await';尽管如此,我还没有把它称为反模式。什么是*绝对*反模式是使用'StartNew'而不指定任务调度器(应该使用'Task.Run'来代替)。另外,你可以做一个强大的例子,返回一个'StartNew' /'Run'任务也是一个反模式(同步代码应该有同步API; *调用者*应该决定是否推送到线程池)。 –
我怀疑意图是使所有三个任务做的工作并行。这是如何可以实现的选项之一:
public async Task<string> GetItemsAsync()
{
var a = Task1();
var b = Task2();
var c = Task3();
return string.Concat(await Task.WhenAll(a, b, c));
}
因为你等待所有人同步。 – Liam
通过等待任务的您正在将其从异步更改为同步,await关键字将暂停当前任务并且不会继续,直到等待完成的任务完成 – MikeT
使用await将使代码同步运行并且还会增加开销创建一个状态机(每次使用'await'),所以它的运行速度也比同步运行慢。 – Igor