4 回答
TA贡献1874条经验 获得超12个赞
一般来说,您的代码是可以的 - 它会比原始代码消耗更多的线程和更多的 CPU,但除非您的网站负载很重,否则它不太可能显着影响整体性能。显然,您需要针对您的特定负载(包括 5-10 倍常规流量的某种压力水平负载)自行测量它。
包装同步方法Task.Run不是最佳实践(请参阅我应该为同步方法公开异步包装器吗?)。只要您的情况可以接受为这种行为交易额外的线程,它就可能对您有用。
如果您只剩下一个同步操作,您可以改为保持同步并在同步步骤结束时等待其余操作,以节省额外的线程:
var dataATask = _dataARepository.GetDataAsync();
var dataBTaskResult = _dataBRepository.GetData();
await Task.WhenAll(dataATask); // or just await dataATask if you have only one.
var viewModel = new ViewModel(dataATask.Result, dataBTaskResult);
TA贡献1804条经验 获得超7个赞
考虑这两种方法。
原来的:
public async Task<ActionResult> Foo()
{
var dataATask = _dataARepository.GetDataAsync();
var dataBTask = Task.Run(_dataBRepository.GetData());
await Task.WhenAll(dataATask, dataBTask);
var viewModel = new ViewModel(dataATask.Result, dataBTask.Result);
return View(viewModel);
}
^此版本将创建一个新线程来调用_dataBRepository.GetData()。附加线程将阻塞,直到调用完成。在等待附加线程完成时,主线程会将控制权交还给 ASP.NET 管道,在那里它可以处理其他用户的请求。
不同的:
public async Task<ActionResult> Foo()
{
var dataATask = _dataARepository.GetDataAsync();
var dataBResult = _dataBRepository.GetData();
await dataATask;
var viewModel = new ViewModel(dataATask.Result, dataBResult);
return View(viewModel);
}
^此版本没有为dataBRepository.GetData(). 但它确实阻塞了主线程。
所以你的选择是:
启动另一个线程,这样您就可以将主线程让给其他任务。
坚持主线。如果其他一些任务需要一个线程,它就必须自己启动。
在这两种情况下,您一次都使用一个线程(大部分情况下)。在这两种情况下,事务都将在两个后端事务中较慢的一个所需的时间内完成。但是原始选项会启动一个新线程并产生当前线程。这似乎是不需要的额外工作。
另一方面,如果该操作需要两个或更多同步后端事务,则原始选项会更快地完成,因为它们可以并行运行。假设他们支持它。如果后端事务是数据库事务并且使用相同的数据库,它们很可能会相互阻塞,在这种情况下您仍然看不到任何好处。
TA贡献1875条经验 获得超3个赞
除了Alexei Levenkov 提到的为异步方法公开同步包装器之外,在 ASP.NET 应用程序上使用Task.Run
弊大于利。每个Task.Run
都会导致 2 个线程池调度和上下文切换,而没有任何好处。
TA贡献1911条经验 获得超7个赞
通常启动一个不同的线程来做一些同步的事情是没有用的,如果你所做的只是等到这个线程完成。
相比:
async Task<int> ProcessAsync()
{
var task = Task.Run(() => DoSomeHeavyCalculations());
int calculationResult = await task;
return calculationResult;
}
和
int ProcessAsync()
{
return DoSomeHeavyCalculations();
}
除了 async 函数使用更多的脑力之外,它会限制函数的重用:只有 async 调用者可以使用它。让您的呼叫者决定是否要异步呼叫您。如果他也无事可做,只能等待,他可以让他的呼叫者决定,等等。
顺便说一句,这正是它的GetData作用:它不会强迫像你这样的调用者异步,它让你可以自由地调用它同步或使用Task.Run调用它异步。
但是,如果您的函数在繁重的计算过程中还有其他事情要做,那么它可能会很有用:
async Task<int> ProcessAsync()
{
var task = Task.Run(() => DoSomeHeavyCalculations());
// while the calculations are being performed, do something else:
DoSomethingElse();
return await task;
}
在您的示例中:如果只有一个“繁重的计算”,请自己执行此操作。如果有几个繁重的计算,您可以考虑使用Task.Run. 但是不要只是命令其他线程做某事而不自己做任何事情。
- 4 回答
- 0 关注
- 158 浏览
添加回答
举报