zoukankan      html  css  js  c++  java
  • C#中对异步方法及异步lambda表达式

    这篇文章的目的并不是系统地介绍C#中的awaitasync关键字,而是针对我遇到的一些问题进行记录。

    背景

    await / async

    C#中可以用async标识方法,表示这个方法是异步的。异步方法的返回值必须是voidTask或者Task<T>。例如:

    public static async Task<int> Method(int i)
    {
        await Task.Delay(1000);
        return i;
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    async修饰的lambda表达式

    我们可以用async修饰lambda表达式,标识这个表达式为异步。

    Func<Task<HttpResponseMessage>> lambda = async () =>
    {
        using (var httpClient = new HttpClient())
        {
            var response = await httpClient.GetAsync("https://www.bing.com/");
            return response;
        }
    };
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    可以看到,用async修饰以后,返回值也变为Task<HttpResponseMessage>

    async标记只是针对方法内部,外部只关心返回值类型。

    异步方法返回的时间

    异步方法在遇到await关键字之后就会返回。例如下面的代码:

    private static Stopwatch stopwatch;
    
    static void Main(string[] args)
    {
        stopwatch = Stopwatch.StartNew();
        Task task = MethodAsync();
        Console.WriteLine($"Main: {stopwatch.ElapsedMilliseconds}");
    }
    
    public static async Task MethodAsync()
    {
        Console.WriteLine("Enter method.");
        Task.Delay(500).Wait();
        Console.WriteLine($"Method will return: {stopwatch.ElapsedMilliseconds}");
        await Task.Delay(1000);
        Console.WriteLine($"End of method: {stopwatch.ElapsedMilliseconds}");
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    MethodAsync()方法会在遇到await时返回。于是就有了如下输出:

    Enter method.
    Method will return: 542
    Main: 544
    • 1
    • 2
    • 3

    Task类的一些方法

    Task.Run(Action action)

    我们可以用Task.Run(Action action)来启动一个任务。

    static void Main(string[] args)
    {
        stopwatch = Stopwatch.StartNew();
        var task = Task.Run(MethodAsync);
        task.Wait();
        Console.WriteLine($"Main: {stopwatch.ElapsedMilliseconds}");
    }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    其中MethodAsync就是上面定义的方法。

    可以推测,MethodAsync执行到第一个await就会返回。Wait()方法也会执行完毕。整段程序执行500多毫秒就应该结束。

    让我们运行一下。

    Enter method.
    Method will return: 544
    End of method: 1546
    Main: 1547
    • 1
    • 2
    • 3
    • 4

    奇怪,MethodAsync返回不久,整个程序就应该结束才是,为什么等待了一秒多,直到MethodAsync全部执行完?

    Task.Run(Func<Task> function)

    原来,Task.Run那里实际调用的是Task.Run(Func<Task> function)这个重载。这个重载返回的Task对象,我们在调用其Wait()成员方法时会等待function返回的Task对象执行结束。我认为应该是为了方便这种情况。

    await Task.Run(async () =>
    {
        using (var httpClient = new HttpClient())
        {
            var response = await httpClient.GetAsync("https://www.bing.com/");
            return response;
        }
    });
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这段代码中,正是由于调用的是Task.Run(Func<Task> function)这个重载,才保证了请求完成后才会继续执行后面的代码。

    System.Threading.Tasks.Parallel类的情况

    System.Threading.Tasks.Parallel类提供了非常方便的并发执行循环的方法。

    Parallel.For(0, 10, i => Console.WriteLine(i));
    • 1

    输出

    0
    2
    6
    4
    5
    8
    9
    7
    3
    1
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    再试试

    Parallel.For(0, 10, async i =>
    {
        await Task.Delay(1000);
        Console.WriteLine(i);
    });
    • 1
    • 2
    • 3
    • 4
    • 5

    输出

    • 1

    是的,输出没有任何内容。

    原因是,ParallelTask不一样,它并不会等待返回的Task,而是在方法返回后就结束。

    所以,如果想确保异步方法完全完成,必须改为同步。

    Parallel.For(0, 10, i =>
    {
        Task.Delay(1000).Wait();
        Console.WriteLine(i);
    });
    • 1
    • 2
    • 3
    • 4
    • 5

    输出

    8
    4
    6
    2
    0
    1
    7
    5
    3
    9
  • 相关阅读:
    ztCreateUserWizard输入密码和设置安全问题
    寻觅在office(确切的说是word) 的工具栏中添加控件的方法,找到了这个控件列表
    vs2005,combox 数据绑定和SelectedIndexChanged事件触发 引发的问题
    今天下载安装了Enterprise Library for .NET Framework 2.0 January 2006,准备试试dataAccess application block
    zt 3DO的历史,让人感慨啊
    iBM,tivoli,flash挺有意思的
    zt科学家发现自转最快中子星 比地球快1亿倍
    c#中读取应用程序路径的方法
    郁闷啊郁闷,为了access的like,折腾了一上午.
    人生
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/14140207.html
Copyright © 2011-2022 走看看