Async方法Await,Task不同的使用方式与执行方式

简介

本篇讲述异步方法在配合await及task时,在不同场景下的不同执行方式。

没有返回值,没有Await(NoReturnNoAwait)

private async static Task Test()
{
    Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    {
        NoReturnNoAwait();
    }
    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.Read();
}
/// <summary>
/// 只有async没有await
/// 跟普通方法没有区别
/// </summary>
private static async void NoReturnNoAwait()
{
    //主线程执行
    Task task = Task.Run(() =>//启动新线程完成任务
    {
        Console.WriteLine($"NoReturnNoAwait Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000);
        Console.WriteLine($"NoReturnNoAwait Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    });
    
    //主线程执行
    Console.WriteLine($"NoReturnNoAwait Sleep after Task,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}

执行顺序如下:
在这里插入图片描述

没有返回值(NoReturn)

private async static Task Test()
{
     Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
     {
         NoReturn();
         for (int i = 0; i < 10; i++)
         {
             Thread.Sleep(300);
             Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId.ToString("00")} i={i}");
         }
     }
     
     Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
     Console.Read();
 }
private static async void NoReturn()
{
    //主线程执行
    Console.WriteLine($"NoReturn Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    TaskFactory taskFactory = new TaskFactory();
    Task task = taskFactory.StartNew(() =>
    {
        Console.WriteLine($"NoReturn Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(3000);
        Console.WriteLine($"NoReturn Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    });
    //task.ContinueWith(t => //这是一个回调
    //{
    //    Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    //});

    await task;
    //主线程到await这里就返回了,执行主线程任务
    //同时task的子线程就开始工作,直到Task完成,然后继续后续任务(后续任务的线程ID不一定是这个子线程,可以是子线程,也可以是其他线程,还可以是主线程) 
    //像什么? 效果上等价于continuewith
    //task.ContinueWith(t =>
    //{
    //    Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    //});

    Console.WriteLine($"NoReturn Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
}

在这里插入图片描述

有await单返回Task(NoReturnTask)

private async static Task Test()
{
    Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    {
        Task t = NoReturnTask();
        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        //t.Wait();//主线程等待Task的完成  阻塞的
        //await t;//await后的代码会由线程池的线程执行  非阻塞
    }
    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.Read();
}
/// <summary>
/// 无返回值  async Task == async void
/// Task和Task<T>能够使用await, Task.WhenAny, Task.WhenAll等方式组合使用。Async Void 不行
/// </summary>
/// <returns></returns>
private static async Task NoReturnTask() //在async/await方法里面如果没有返回值,默认返回一个Task
{
    //这里还是主线程的id
    Console.WriteLine($"NoReturnTask Sleep before await,ThreadId={Thread.CurrentThread.ManagedThreadId}");

    Task task = Task.Run(() =>
    {
        Console.WriteLine($"NoReturnTask Sleep3000 before,ThreadId={Thread.CurrentThread.ManagedThreadId}");
        Thread.Sleep(1000);
        Console.WriteLine($"NoReturnTask Sleep3000 after,ThreadId={Thread.CurrentThread.ManagedThreadId}");
    });
    await task;
    Console.WriteLine($"NoReturnTask Sleep after await,ThreadId={Thread.CurrentThread.ManagedThreadId}");
 
}

在这里插入图片描述

有async并返回有参数Task并在外部使用task等待( SumFactoryTask)

private async static Task Test()
{
    Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    
    {
        Task<long> t = SumAsync();
        Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
        long lResult = t.Result;//访问result,阻塞式   主线程等待所有的任务挖成 //如果访问Result,就相当于是同步方法!
        t.Wait();//等价于上一行,阻塞式--同步
        //await t;//非阻塞,
    }
   
    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.Read();
}
/// <summary>
/// 带返回值的Task  
/// 要使用返回值就一定要等子线程计算完毕
/// </summary>
/// <returns>async 就只返回long</returns>
private static async Task<long> SumAsync()
{
    Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    long result = 0;

    await Task.Run(() =>
    {
        for (int k = 0; k < 10; k++)
        {
            Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(1000);
        }
        for (long i = 0; i < 999_999_999; i++)
        {
            result += i;
        }
    });

    Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");    
    return result;
}

在这里插入图片描述

没有有async并返回有参数Task并在外部使用task等待(SumFactoryNoAsyncTask)

private async static Task Test()
{
    Console.WriteLine($"当前主线程id={Thread.CurrentThread.ManagedThreadId.ToString("00")}");
    
    {
         Task<long> t = SumAsync();
         Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
         long lResult = t.Result;//没有await和async 普通的task
         t.Wait();
    }
   
    Console.WriteLine($"Main Thread Task ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    Console.Read();
}
/// <summary>
/// 带返回值的Task  
/// 要使用返回值就一定要等子线程计算完毕
/// </summary>
/// <returns>async 就只返回long</returns>
private static async Task<long> SumAsync()
{
    Console.WriteLine($"SumAsync 111 start ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
    long result = 0;

    await Task.Run(() =>
    {
        for (int k = 0; k < 10; k++)
        {
            Console.WriteLine($"SumAsync {k} await Task.Run ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");
            Thread.Sleep(1000);
        }
        for (long i = 0; i < 999_999_999; i++)
        {
            result += i;
        }
    });

    Console.WriteLine($"SumFactory 111   end ManagedThreadId={Thread.CurrentThread.ManagedThreadId}");    
    return result;
}

在这里插入图片描述

结论

        当主线程发现需要启用子线程时,子线程的内容会自动执行,主线程不受影响继续向下执行。
        当主线程碰到await时,主线程会返回到上一个方法中,当前方法中未执行的代码会被打包交给线程池,并由线程池分配给子线程来执行(但不一定与await后的线程是同一个子线程)。
        当主线程遇到Task<>.Result(或Result<>.Wait )时,会等待子线程执行过后再继续执行。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值