目录
简介
本篇讲述异步方法在配合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 )时,会等待子线程执行过后再继续执行。