目录

C#-Task详细学习记录(包含一个WPF_Demo)

一、Task 核心概念

Task 本质:对“未来结果”的一个抽象(Promise) + 异步调度机制

它是 C# async/await 的基础。

二、Task 常用 API 分类

1.创建任务

Task.Run

在线程池上启动一个任务。

用于在线程池执行任务(CPU 密集)

await Task.Run(() => DoWork());

Task.FromResult

返回一个已完成的成功任务

return Task.FromResult(42);

适用于:已有结果但需要返回 Task

Task.FromException

返回一个已失败的任务

return Task.FromException<int>(new Exception("error"));

Task.FromCanceled

返回一个已取消的任务

return Task.FromCanceled<int>(token);

TaskCompletionSource(重要)

var tcs = new TaskCompletionSource<int>();
tcs.SetResult(100);
await tcs.Task;

用途:回调转 async

2.任务组合

Task.WhenAll

等待所有任务完成(全部成功才算成功)

await Task.WhenAll(task1, task2);

特点:全部完成才返回

Task.WhenAny

等待任意一个任务完成(谁先完成就返回谁)

var t = await Task.WhenAny(task1, task2);

特点:谁先完成返回谁

3. 时间控制

Task.Delay

异步等待一段时间(不会阻塞线程)

await Task.Delay(1000);

Task.Yield

强制让出当前线程,稍后继续指向(用于避免同步上下文阻塞)

await Task.Yield();

4.状态与结果

推荐:

var result = await task;

不推荐:

var r = task.Result; // 可能死锁
task.Wait();

5. 实例方法(较少用)

ContinueWith

当前任务完成后继续执行另一个任务

task.ContinueWith(t => Console.WriteLine("done"));

已被 await 替代

三、关键机制解析

1. 为什么 await 不会死锁?

因为:

  • await 不阻塞线程
  • 状态机 + 回调机制

而 .Result / Wait:

  • 阻塞线程
  • 导致 UI 线程互相等待

2. async void 为什么危险?

  • 无法捕获异常
  • 无法 await
  • 无法控制生命周期

仅用于:事件处理

3.ConfigureAwait(false)

await task.ConfigureAwait(false);

作用:不捕获 UI 上下文

好处:

  • 防死锁
  • 提升性能

适用于:库代码 / 后台逻辑

四、常见错误总结

  • 用 Task.Run 包裹 I/O

  • 使用 .Result

  • 忘记 await

  • async void 滥用

五、WPF 实战 Demo(完整示例)

场景说明

点击按钮后:

  • 并发执行多个任务
  • 显示进度
  • 支持取消
  • 使用 WhenAll / WhenAny / Delay / Run / ContinueWith
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Task Demo" Height="300" Width="400">
    <StackPanel Margin="20">
        <Button Name="StartBtn" Click="StartBtn_Click" Content="Start" />
        <Button Name="CancelBtn" Click="CancelBtn_Click" Content="Cancel" />
        <TextBlock Name="Output" Margin="0,20,0,0" />
    </StackPanel>
</Window>
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace WpfApp
{
    public partial class MainWindow : Window
    {
        private CancellationTokenSource _cts;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void StartBtn_Click(object sender, RoutedEventArgs e)
        {
            _cts = new CancellationTokenSource();
            Output.Text = "Running...";

            try
            {
                var tasks = Enumerable.Range(1, 3).Select(i => DoWorkAsync(i, _cts.Token));

                // WhenAny 示例
                var first = await Task.WhenAny(tasks);
                Output.Text = $"First finished: {first.Result}";

                // WhenAll 示例
                var results = await Task.WhenAll(tasks);

                Output.Text += "\nAll done: " + string.Join(",", results);
            }
            catch (Exception ex)
            {
                Output.Text = ex.Message;
            }
        }

        private void CancelBtn_Click(object sender, RoutedEventArgs e)
        {
            _cts?.Cancel();
        }

        private async Task<int> DoWorkAsync(int id, CancellationToken token)
        {
            // 模拟异步 I/O
            await Task.Delay(1000 * id, token);

            // CPU 操作
            await Task.Run(() =>
            {
                Thread.Sleep(500);
            });

            // ContinueWith 示例
            await Task.Delay(100).ContinueWith(t => { });

            token.ThrowIfCancellationRequested();

            return id;
        }
    }
}

六、Demo 涵盖知识点

  • Task.Run

  • Task.Delay

  • Task.WhenAll

  • Task.WhenAny

  • ContinueWith

  • CancellationToken

  • async/await

七、最终总结

Task = 异步世界的核心抽象

掌握关键:

  • await(核心)

  • WhenAll / WhenAny(并发)

  • Task.Run(CPU)

  • Delay(时间控制)

  • 避免 .Result

Task
├── 创建任务
│   ├── Task.Run              👉 开线程池任务(最常用)
│   ├── Task.FromResult       👉 已完成任务(有返回值)
│   ├── Task.FromException    👉 已失败任务
│   ├── Task.FromCanceled     👉 已取消任务
│   └── TaskCompletionSource 👉 手动控制任务
├── 任务组合
│   ├── Task.WhenAll         👉 等全部完成(并发汇总)
│   └── Task.WhenAny         👉 等任意完成(抢最快)
├── 时间控制
│   ├── Task.Delay           👉 异步延迟(不阻塞)
│   └── Task.Yield           👉 主动让出线程
├── 状态/结果
│   ├── Task.CompletedTask   👉 已完成(无返回)
│   ├── task.Result          👉 获取结果(⚠️阻塞)
│   └── await task           👉 推荐方式
├── 同步等待(⚠️危险)
│   ├── task.Wait()
│   ├── Task.WaitAll()
│   └── Task.WaitAny()
└── 延续/链式
    └── ContinueWith         👉 旧式写法(基本被 await 替代)

八、进阶建议

下一步建议深入:

  • async/await 状态机原理
  • SynchronizationContext
  • 线程池调度机制