如何处理同步的方法/任务异步使用/等待 [英] How to deal with synchronous method/task using async/await
问题描述
我想了解如何使用.NET 4.5异步/等待关键字任务,在它的核心是同步的。即一些复杂的数学计算。我已经使用了的Thread.Sleep来模拟在下面的示例中的行动。我的问题是那里你可以做出这样一个异步方法这种方法的行为方式?如果不这样做,你只需要做什么,我在ThisWillRunAsyncTest方法做了,做类似的东西Task.Factory.StartNew上同步方法。是否有这样做的更清洁的方式?
使用的System.Threading;
使用System.Collections.Generic;
使用System.Threading.Tasks;使用NUnit.Framework;[的TestFixture]
公共类AsyncAwaitTest
{
[测试]
//这个测试将需要1秒运行,因为它运行异步
//是否有更好的方式开始了同步任务,并将它并行运行。
公共异步无效ThisWillRunAsyncTest()
{
VAR任务=新的List<任务>();
的for(int i = 0;我小于5;我++)
{
tasks.Add(Task.Factory.StartNew(()=> this.RunTask()));
} 等待Task.WhenAll(任务);
} [测试]
//这个测试将需要大约5秒运行,因为它运行同步。
//如果运行任务在它有一个的await,这这将同步运行。
公共异步无效ThisWillRunSyncTest()
{
VAR任务=新的List<任务>();
的for(int i = 0;我小于5;我++)
{
tasks.Add(this.RunTask());
} 等待Task.WhenAll(任务);
} //这就是我想要并行运行一些同步任务的一个例子。
//有什么我可以在这个方法中,使async关键字的工作吗?即从调用时,这将异步运行ThisWillRunSyncTest
公共异步任务RunTask()
{
Thread.sleep代码(1000);
}
}
作为一般规则,如果你的平行的工作要做,你应该使用平行
或并行LINQ。
有一些时候很方便治疗CPU密集型的工作,仿佛它是异步的(即在后台线程上运行它)。这是 Task.Run
是(避免使用 StartNew
,因为我的describe~~V在我的博客)。
同步方法应该有同步的方法签名:
公共无效RunTask()
{
Thread.sleep代码(1000);
}
他们应该只被包裹在 Task.Run
如果调用code需要它(也就是说,它是一个UI组件的一部分,如视图模型)
VAR任务=新的List<任务>();
的for(int i = 0;我小于5;我++)
{
tasks.Add(Task.Run(()=> this.RunTask()));
}
等待Task.WhenAll(任务);
这里的原则是, Task.Run
应在调用中使用,不落实;我去到更多的细节在我的博客。
请注意,如果您有任何真正的复杂性,您应该使用并行
或并行LINQ,而不是 Task.Run $的集合C $ C>任务。
Task.Run
是罚款小东西,但它不具备所有的智慧并行类型做。所以,如果这是一个库的一部分(不一定在UI线程中运行),那么我推荐使用并行
:
的Parallel.For(0,5,_ => this.RunTask());
作为最后一个侧面说明,异步单元测试方法应异步任务
,而不是异步无效
。 NUnit的V3已经删除了支持异步无效
单元测试方法。
I'm trying to understand how to use the .net 4.5 async/await keywords with a Task that at it's core is synchronous. I.e. some sort of complex math calculation. I've used a Thread.Sleep to simulate that action in the example below. My question is there a way you can make such a method act like an async method? If not do you just need to do what I did in the ThisWillRunAsyncTest method and do something like Task.Factory.StartNew on that sync method. Is there a cleaner way of doing this?
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
using NUnit.Framework;
[TestFixture]
public class AsyncAwaitTest
{
[Test]
//This test will take 1 second to run because it runs asynchronously
//Is there a better way to start up a synchronous task and have it run in parallel.
public async void ThisWillRunAsyncTest()
{
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(Task.Factory.StartNew(() => this.RunTask()));
}
await Task.WhenAll(tasks);
}
[Test]
//This test will take 5 seconds to run because it runs synchronously.
//If the Run Task had an await in it, this this would run synchronously.
public async void ThisWillRunSyncTest()
{
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(this.RunTask());
}
await Task.WhenAll(tasks);
}
//This is just an example of some synchronous task that I want to run in parallel.
//Is there something I can do in this method that makes the async keyword work? I.e. this would run asynchronously when called from ThisWillRunSyncTest
public async Task RunTask()
{
Thread.Sleep(1000);
}
}
As a general rule, if you have parallel work to do, you should be using Parallel
or parallel LINQ.
There are times when it's convenient to treat CPU-bound work as though it were asynchronous (i.e., running it on a background thread). This is what Task.Run
is for (avoid using StartNew
, as I describe on my blog).
Synchronous methods should have synchronous method signatures:
public void RunTask()
{
Thread.Sleep(1000);
}
They should only be wrapped in Task.Run
if the calling code requires it (i.e., it is part of a UI component such as a view model):
var tasks = new List<Task>();
for (int i = 0; i < 5; i++)
{
tasks.Add(Task.Run(() => this.RunTask()));
}
await Task.WhenAll(tasks);
The principle here is that Task.Run
should be used in the invocation, not the implementation; I go into more details on my blog.
Note that if you have any real complexity, you should be using Parallel
or parallel LINQ instead of a collection of Task.Run
tasks. Task.Run
is fine for small stuff but it doesn't have all the smarts the parallel types do. So, if this is part of a library (and not necessarily running on a UI thread), then I'd recommend using Parallel
:
Parallel.For(0, 5, _ => this.RunTask());
As a final side note, asynchronous unit test methods should be async Task
, not async void
. NUnit v3 has already removed support for async void
unit test methods.
这篇关于如何处理同步的方法/任务异步使用/等待的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!