异步编程(四):async/await模式之await表达式

2019-02-24  本文已影响0人  曦航老袁

await表达式作用是指定异步执行的任务,由await关键字和一个空闲对象(简称任务)组成。这个任务可能是一个Task类型的对象,也可能不是。默认状态下,这个任务是在当前线程异步执行的。

await task

任务是一个awaitable类型的对象。awaitable类型是指包含GetAwaiter方法的类型,该方法没有参数,返回一个称为awaiter类型的对象。awaiter类型包括以下成员:

在实际使用过程中,大多数时候你并不需要构建自己的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);
上一篇下一篇

猜你喜欢

热点阅读