我可以 运行 将代码同步为异步以获得性能吗?
Can I run sync code as async to gain performance?
我阅读了很多讨论 Async/Await 在 C# 中的用法的论坛、教程和博客。我读得越多,它就越混乱。
另外,人们主要谈论在同步方法中调用异步的东西,而不是在异步方法中调用同步的东西。
由于我是一名初级开发人员并且没有太多异步编程经验,所以我将 post 在这里提出一个新问题并希望得到一些启发。
考虑一下:
我有一个 Web API 端点,可以进行一些计算和模型构建以及 return 一些数据。
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff2Task = CalculateStuff2();
Task<Data> stuff3Task = CalculateStuff3();
return Json(
new
{
stuff1 = await stuff1Task,
stuff2 = await stuff2Task,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet
);
}
private async Task<Data> CalculateStuff1()
{
return await SomeAsyncCalculation();
}
private async Task<Data> CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
Task<Data> dataTask1 = SomeAsyncCalculation();
Task<Data> dataTask2 = AnotherAsyncCalculation();
Data data1 = await dataTask1;
Data data2 = await dataTask2;
Data combindedData = SyncMethodToCombineData(data1, data2);
return combindedData;
}
为什么我考虑混合异步和同步代码是为了获得更好的性能。
在这种情况下,假设 SomeAsyncCalculation()
、SomeSyncCalculation()
和 AnotherAsyncCalculation()
是相当昂贵的方法。我的目标是让方法 运行 稍微并行一些以获得更快的响应时间。
我知道最好“一直异步”,但说实话,重建项目的一半并不总是优先事项或可能性。
此外,我可能与不支持异步操作的其他系统进行了一些集成。
我收到的关于 CalculateStuff2()
的警告增加了混乱。 :
this async method lacks 'await' operators and will run synchronously
据我了解,“async”关键字仅适用于包装方法并允许我使用 await 关键字。它还允许我只 return 数据,我不需要管理任务 returning 结果。它还处理异常。
Task<TResult>
return 类型使方法在不同的线程上执行(尽管不能保证它会在不同的线程上执行)。
结论性问题:
1. 不使用 await (CalculateStuff2()
) 运行 的异步方法是否会在它自己的线程上同步(如果它 运行s 在另一个线程上,因为它是 Task
) 还是会在 API 调用的主线程中 运行,无论如何总是阻塞它?
2。在没有 await 的情况下使用 async 只是为了有一个开箱即用的包装好的任务方法是不好的做法吗?
您不需要 async
同步方法。 async
生成状态机,这是一种冗余,以防您不需要 await
。
考虑这个稍微优化的示例。
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff3Task = CalculateStuff3();
Data stuff2data = CalculateStuff2(); // run sync method after launching async ones
return Json(new
{
stuff1 = await stuff1Task,
stuff2 = stuff2data,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet);
}
private Task<Data> CalculateStuff1() // optimized
{
return SomeAsyncCalculation();
}
private Data CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
//use combinator to simplify the code
Data[] data = await Task.WhenAll(SomeAsyncCalculation(), AnotherAsyncCalculation());
Data combindedData = SyncMethodToCombineData(data[0], data[1]);
return combindedData;
}
还要考虑区分 CPU 绑定和 IO 绑定操作,请查看 this article。有不同的异步方法,具体取决于您要启动的具体内容。
直接回答
- Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
是的,它将 运行 在调用者线程上同步。如果你想 运行 在它自己的线程上使用一些同步方法,使用 Task.Run()
:
Task<Data> stuff2Task = Task.Run(() => CalculateStuff2());
然后await
它。
- Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
是的,这是不好的做法。冗余状态机产生的开销在这种情况下毫无价值。
我阅读了很多讨论 Async/Await 在 C# 中的用法的论坛、教程和博客。我读得越多,它就越混乱。 另外,人们主要谈论在同步方法中调用异步的东西,而不是在异步方法中调用同步的东西。
由于我是一名初级开发人员并且没有太多异步编程经验,所以我将 post 在这里提出一个新问题并希望得到一些启发。
考虑一下:
我有一个 Web API 端点,可以进行一些计算和模型构建以及 return 一些数据。
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff2Task = CalculateStuff2();
Task<Data> stuff3Task = CalculateStuff3();
return Json(
new
{
stuff1 = await stuff1Task,
stuff2 = await stuff2Task,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet
);
}
private async Task<Data> CalculateStuff1()
{
return await SomeAsyncCalculation();
}
private async Task<Data> CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
Task<Data> dataTask1 = SomeAsyncCalculation();
Task<Data> dataTask2 = AnotherAsyncCalculation();
Data data1 = await dataTask1;
Data data2 = await dataTask2;
Data combindedData = SyncMethodToCombineData(data1, data2);
return combindedData;
}
为什么我考虑混合异步和同步代码是为了获得更好的性能。
在这种情况下,假设 SomeAsyncCalculation()
、SomeSyncCalculation()
和 AnotherAsyncCalculation()
是相当昂贵的方法。我的目标是让方法 运行 稍微并行一些以获得更快的响应时间。
我知道最好“一直异步”,但说实话,重建项目的一半并不总是优先事项或可能性。 此外,我可能与不支持异步操作的其他系统进行了一些集成。
我收到的关于 CalculateStuff2()
的警告增加了混乱。 :
this async method lacks 'await' operators and will run synchronously
据我了解,“async”关键字仅适用于包装方法并允许我使用 await 关键字。它还允许我只 return 数据,我不需要管理任务 returning 结果。它还处理异常。
Task<TResult>
return 类型使方法在不同的线程上执行(尽管不能保证它会在不同的线程上执行)。
结论性问题:
1. 不使用 await (CalculateStuff2()
) 运行 的异步方法是否会在它自己的线程上同步(如果它 运行s 在另一个线程上,因为它是 Task
) 还是会在 API 调用的主线程中 运行,无论如何总是阻塞它?
2。在没有 await 的情况下使用 async 只是为了有一个开箱即用的包装好的任务方法是不好的做法吗?
您不需要 async
同步方法。 async
生成状态机,这是一种冗余,以防您不需要 await
。
考虑这个稍微优化的示例。
public async Task<JsonResult> GetData()
{
Task<Data> stuff1Task = CalculateStuff1();
Task<Data> stuff3Task = CalculateStuff3();
Data stuff2data = CalculateStuff2(); // run sync method after launching async ones
return Json(new
{
stuff1 = await stuff1Task,
stuff2 = stuff2data,
stuff3 = await stuff3Task
}, JsonRequestBehavior.AllowGet);
}
private Task<Data> CalculateStuff1() // optimized
{
return SomeAsyncCalculation();
}
private Data CalculateStuff2()
{
return SomeSyncCalculation();
}
private async Task<Data> CalculateStuff3()
{
//use combinator to simplify the code
Data[] data = await Task.WhenAll(SomeAsyncCalculation(), AnotherAsyncCalculation());
Data combindedData = SyncMethodToCombineData(data[0], data[1]);
return combindedData;
}
还要考虑区分 CPU 绑定和 IO 绑定操作,请查看 this article。有不同的异步方法,具体取决于您要启动的具体内容。
直接回答
- Will the async method that does not use await (CalculateStuff2()) run synchronously on it's own thread (if it runs on another thread because it is a Task) or will it run in the main thread of the API call, and always block it no matter what?
是的,它将 运行 在调用者线程上同步。如果你想 运行 在它自己的线程上使用一些同步方法,使用 Task.Run()
:
Task<Data> stuff2Task = Task.Run(() => CalculateStuff2());
然后await
它。
- Is it bad practice to use async without await just to have a nicely wrapped task method out of the box?
是的,这是不好的做法。冗余状态机产生的开销在这种情况下毫无价值。