多线程--await/async

8 篇文章 0 订阅

1.await/async简述

  • await/async是C#保留关键字,通常成对出现
  • async修饰方法,可以单独出现,对原来的方法没有任何改变,但会警告
  • await在方法体,只能出现在task/async方法前面,单独使用await会报错
  • async位于方法修饰符之后,返回类型之前

2.相关例子

2.1.单独使用async

  • 代码如下:
/// <summary>
///方法带async,但方法体中Task前面不带await(与普通方法执行一样,只不过会警告)
/// </summary>
static async void AsyncNoAwait()
{
    Console.WriteLine($"AsyncNoAwait start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    Task.Run(() =>
    {
        Console.WriteLine($"AsyncNoAwait--Task start ThreadId:{Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000);
        Console.WriteLine($"AsyncNoAwait--Task end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
    });

    Console.WriteLine($"AsyncNoAwait end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}
  • 在控制台输出如下:

  • 结论:使用方式与普通方法无异,只是会有警告

2.2.await和async同时使用

await在方法内部位于Task前面,当前线程遇到await则跳出方法,然后继续执行,而await Task.Run()之后的代码都要等Task执行完成之后执行,效果与Task.Run()的回调一样

  • 代码如下:
static void AsyncAwaitTest()
{
    Console.WriteLine($"AsyncAwaitTest start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    //线程执行到AsyncWithAwait方法里面的await语句之后,跳出此方法,继续之后后面的代码
    AsyncWithAwait(); 

    Console.WriteLine($"AsyncAwaitTest end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}


/// <summary>
/// await/async同时使用
/// 此await的作用就是让当前线程不执行后面的代码,而是跳出方法体,去执行调用次方法后面的代码,
/// 而await后面的代码在await 异步任务执行完成之后调用,类似回调
/// </summary>
static async void AsyncWithAwait()
{
    Console.WriteLine($"AsyncWithAwait start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    //执行到此处,当前线程就会跳出当前方法
    await Task.Run(() =>
    {
        Console.WriteLine($"AsyncWithAwait--Task start ThreadId:{Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000);
        Console.WriteLine($"AsyncWithAwait--Task end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
    });

    //此处的输出等上面的Task.Run 执行结束之后执行
    Console.WriteLine($"AsyncWithAwait end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}
  • 控制台输出如下:

  • 结论:当前线程1执行遇到await,不执行await后面的代码,而await Task.Run()新开一个线程3执行lambda,所以之后两个线程是并发执行的,互不干扰,只不过是先后顺序而已,至于Task.Run()后面的代码,是在Task.Run()执行完成之后执行的,可能会是当前线程也可能会新开一个线程

2.3.async方法上加多Task

  • 代码如下:
static void AsyncAwaitTest()
{
    Console.WriteLine($"AsyncAwaitTest start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    //线程执行到AsyncWithAwait方法里面的await语句之后,跳出此方法,继续之后后面的代码
    Task task = TaskAsyncNoRerturn(); 
    //wait会阻塞当前线程,直到TaskAsyncNoRerturn方法中await task后面的同步方法执行完成
    task.Wait();

    Console.WriteLine($"AsyncAwaitTest end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}

/// <summary>
 /// 方法带Task,但方法没有返回值
 /// 返回的Task包含了整个调用的方法,如果使用Task.wait(),将等待方法同步线程执行完毕
 /// </summary>
 /// <returns></returns>
 static async Task TaskAsyncNoRerturn()
 {
     Console.WriteLine($"TaskAsyncNoRerturn start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

     Task task = Task.Run(() =>
     {
         Console.WriteLine($"TaskAsyncNoRerturn--Task start ThreadId:{Thread.CurrentThread.ManagedThreadId}");
         Thread.Sleep(1000);
         Console.WriteLine($"TaskAsyncNoRerturn--Task end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
     });

     await task; //方法声明中的Task与当前task没有任何关系

    //调用此方法,如果使用返回值task.wait()阻塞线程,将等到后面同步代码执行完毕才会跳过task.wait()
    for (int i = 0; i < 2; i++)
    {
        Console.WriteLine($"{i} ThreadId:{Thread.CurrentThread.ManagedThreadId}");
    Thread.Sleep(1000);
    }


    Console.WriteLine($"TaskAsyncNoRerturn end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}
  • 控制台输出如下:

  • 结论:在async方法中加入Task并不是指方法需要return,而是调用之后会自动返回一个Task类型的对象(暂时作为 task),调用task.wait()之后,会阻塞当前线程,直到async方法内部的同步代码执行完成

备注:async方法内部的同步代码:指的是在await Task.Run()之后的代码是没有再创建任何线程去执行的代码

2.4.带返回值的async方法

方法声明:访问修饰符 async Task<返回值类型> 方法名

例子:public async Task<int> Method

  • 代码如下:
static void AsyncAwaitTest()
{
    Console.WriteLine($"AsyncAwaitTest start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    Task<int> task = TaskAsyncWithRerturn();
    //调用task.Result获取返回值,会阻塞当前线程,指定返回值计算完成
    Console.WriteLine($"TaskAsyncWithRerturn的返回值:{task.Result}");

    Console.WriteLine($"AsyncAwaitTest end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
}

/// <summary>
/// TaskAsyncWithRerturn方法返回int类型的值
/// 调用TaskAsyncWithRerturn返回,会返回一个Task<int>对象
/// 调用者想要获取返回值,就得等task线程计算完毕,就是会阻塞调用线程 
/// </summary>
/// <returns></returns>
static async Task<int> TaskAsyncWithRerturn()
{
    Console.WriteLine($"TaskAsyncWithRerturn start ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    int result = 0;

    Task task = Task.Run(() =>
    {
        Console.WriteLine($"TaskAsyncWithRerturn--Task start ThreadId:{Thread.CurrentThread.ManagedThreadId}");
        for (int i = 0; i < 200; i++)
        {
            result += i;
            Thread.Sleep(10);
        }
        Console.WriteLine($"TaskAsyncWithRerturn--Task end ThreadId:{Thread.CurrentThread.ManagedThreadId}");
    });
    await task;

    Console.WriteLine($"TaskAsyncWithRerturn end ThreadId:{Thread.CurrentThread.ManagedThreadId}");

    return result;
}
  • 控制台输出如下:

  • 结论:调用带返回值的async方法,如果要获取其返回值,就会阻塞当前线程,直到async方法中的返回值计算完毕

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值