await表达式作用是指定异步执行的任务,由await关键字和一个空闲对象(简称任务)组成。这个任务可能是一个Task类型的对象,也可能不是。默认状态下,这个任务是在当前线程异步执行的。
await task
任务是一个awaitable类型的对象。awaitable类型是指包含GetAwaiter方法的类型,该方法没有参数,返回一个称为awaiter类型的对象。awaiter类型包括以下成员:
- bool IsCompleted{ get; }
- void OnCompleted{ Action };
- void GetResult(); 或者 T GetResult();
在实际使用过程中,大多数时候你并不需要构建自己的awaitable。你只需要使用Task类型就足够了。
在.NET 4.5中,微软发布了大量新的和修订的异步方法(在BCL中),它们可以返回Task<T>类型的对象。将它们放置到await语句中,就可以在当前线程中异步执行。
Uri site = new Uri(“http://www.baidu.com”);
WebClient wc = new WebClient();
string value = await wc.DownLoadStringTaskAsync(site);
但更多时候我们还是需要构建自己方法,做为await表达式的任务。最简单的方式是使用Task.Run方法。有一点需要特别注意:它是在不同的线程上运行你的方法!
例如:Task.Run( Func<TResult> func)
可以看出,你的方法传递需要基于该方法创建一个委托。下面将用一段代码显示通常使用的三种方式:
class MyClass
{
public int Get10()
{
return 10;
}
public async Task DoWorkAsync()
{
Func<int> ten = new Func<int>(Get10);
int a = await Task.Run( ten );
int b = await Task.Run( new Func<int>(Get10);
int c = await Task.Run(() => { return 10; });
Console.WriteLine( “{0} {1} {2}”, a, b, c);
}
}
class Program
{
static void Main()
{
Task t = (new MyClass()).DoWorkAsync();
t.Wait();
}
}
上面的示例中我们使用的Task.Run的签名以Func<TResult>为参数,才方法共有8个重载:
返回类型 | 签名 |
---|---|
Task | Run( Action action) |
Task | Run( Action action, CancellationToken token ) |
Task<TResult> | Run( Func<TResult> function) |
Task<TResult> | Run( Func<TResult> function, CancellationToken token ) |
Task | Run( Func<TResult> function) |
Task | Run( Func<TResult> function, CancellationToken token ) |
Task<TResult> | Run( Func<TResult> function) |
Task<TResult> | Run( Func<TResult> function, CancellationToken token ) |
可以作为Task.Run方法第一个参数的委托类型包括:
委托类型 | 签名 | 含义 |
---|---|---|
Action | void Action() | 无参数且无返回值的方法 |
Func<TResult> | TResult Func() | 无参数但有返回值的方法 |
Func<Task> | Task Func() | 无参数返回简单Task对象的方法 |
Func<Task<TResult>> | Task<TReslut> Func() | 无参数返回Task<T>类型对象的方法 |
下面举一个例子展示4个不同的await语句:
static class MyClass
{
public static async Task DoWorkAsync()
{
await Task.Run(() => Console.WriteLine(5.ToString()));
Console.WriteLine((await Task.Run(() => 6)).ToString());
await Task.Run(() => Task.Run(() => Console.WriteLine(7.ToString())));
int value = await Task.Run(() => Task.Run(() => 8));
Console.WriteLine(value.ToString());
}
}
class Program
{
static void Main()
{
Task t = MyClass.DoWorkAsync();
t.Wait();
Console.WriteLine("Press Enter key to exit.");
Console.Read();
}
}
代码运行结果:
5
6
7
8
在能使用任何表达式的地方,都可以使用await表达式(当然要位于异步方法内)。上述的语句中,第一个和第三个实例将await表达式用作语句;第二个实例将await表达式用作WriterLine方法的参数;第四个实例将await表达式用作赋值语句的右端。
假设我们的某个方法不符合这四种委托形式。例如有一个GetSum方法以两个int值作为参数输入,并返回这两个值的和。这与上述四种可接受的委托均不兼容。解决方案是用可以接受的Fun委托形式创建一个Lambda方法。代码如下:
int value = await Task.Run(()=>GetSum(5,6));
Console.WriteLin(value.tostring);
网友评论