.NET中的Task

1. 创建Task:

Console.WriteLine("Before task1, with thread id: {0}", Environment.CurrentManagedThreadId);

Console.WriteLine("=== Time before tasks begin ===");
Console.WriteLine(DateTime.Now.ToLongTimeString());

Task task1 = Task.Factory.StartNew(() =>
{
    Console.WriteLine("In task1, with thread id: {0}", Environment.CurrentManagedThreadId);
    Thread.Sleep(10000);
});

Console.WriteLine("Before task2 (after task1), with thread id: {0}", Environment.CurrentManagedThreadId);

Task task2 = Task.Factory.StartNew(() =>
{
    Console.WriteLine("In task2, with thread id: {0}", Environment.CurrentManagedThreadId);
    Thread.Sleep(10000);
});

Console.WriteLine("After task2, with thread id: {0}", Environment.CurrentManagedThreadId);

// Since a console application otherwise terminates, wait for both tasks to complete.
Task.WaitAll(new Task[] { task1, task2 });

Console.WriteLine("=== Time after tasks finish ===");
Console.WriteLine(DateTime.Now.ToLongTimeString());

运行得到如下结果:

Before task1, with thread id: 1
=== Time before tasks begin ===
7:05:13 PM
Before task2 (after task1), with thread id: 1
After task2, with thread id: 1
In task1, with thread id: 3
In task2, with thread id: 4
=== Time after tasks finish ===
7:05:23 PM

关于结果的几点说明:(1)两个task运行的不在主线程中;(2)每个task需要10秒,两个task也只需要10秒。在多核(多CPU)机器上,能提高性能。

2. 一个task可以创建一个或者多个子task。我们还可以设定task之间的依赖关系。比如:

private static void Process(string name, int secondsToSleep)
{
    Console.WriteLine("In processing {0}, start at time: {1}", name,
        DateTime.Now.ToLongTimeString());

    Thread.Sleep(secondsToSleep * 1000);

    Console.WriteLine("In processing {0}, end at time: {1}", name,
        DateTime.Now.ToLongTimeString());
}

static void Main(string[] args)
{
    var solution = new Task(() =>
    {
        var taskFactory = new TaskFactory(TaskCreationOptions.AttachedToParent,
            TaskContinuationOptions.AttachedToParent);

        var C = taskFactory.StartNew(() => Process("C", 10));
        var E = taskFactory.StartNew(() => Process("E", 10));
        var F = taskFactory.StartNew(() => Process("F", 10));
        var B = C.ContinueWith(t => Process("B", 10));
        var D = taskFactory.ContinueWhenAll(new Task[] { E, F },
            tasks => Process("D", 10));
        var A = taskFactory.ContinueWhenAll(new Task[] { B, D },
            tasks => Process("A", 10));

    });

    solution.Start();
    solution.Wait();
}

输出为:

In processing C, start at time: 8:02:09 PM
In processing E, start at time: 8:02:09 PM
In processing F, start at time: 8:02:09 PM
In processing F, end at time: 8:02:19 PM
In processing C, end at time: 8:02:19 PM
In processing E, end at time: 8:02:19 PM
In processing B, start at time: 8:02:19 PM
In processing D, start at time: 8:02:19 PM
In processing B, end at time: 8:02:29 PM
In processing D, end at time: 8:02:29 PM
In processing A, start at time: 8:02:29 PM
In processing A, end at time: 8:02:39 PM

实验机器的CPU为四核。不同机器的输出可能略有不同。

3. await

private static async Task<int> LongTaskAsyn()
{
    Console.WriteLine("In DoTask, before GetStringAsync.");
    Console.WriteLine("Thread id: {0}.\n", Environment.CurrentManagedThreadId);

    Task<String> task = new HttpClient().GetStringAsync("http://www.microsoft.com");
    String text = await task;

    Console.WriteLine("In DoTask, after GetStringAsync.");
    Console.WriteLine("Thread id: {0}.\n", Environment.CurrentManagedThreadId);

    return text.Length;
}

static void Main(string[] args)
{
    Console.WriteLine("In Main, before LongTaskAsyn.");
    Console.WriteLine("Thread id: {0}.\n", Environment.CurrentManagedThreadId);

    Task<int> task = LongTaskAsyn();

    Console.WriteLine("In Main, after LongTaskAsyn.");
    Console.WriteLine("Thread id: {0}.\n", Environment.CurrentManagedThreadId);

    var result = task.GetAwaiter().GetResult();
}

运行结果:

In Main, before LongTaskAsyn.
Thread id: 1.

In DoTask, before GetStringAsync.
Thread id: 1.

In Main, after LongTaskAsyn.
Thread id: 1.

In DoTask, after GetStringAsync.
Thread id: 9.
结果说明:(1)调用async函数,在函数执行结束前就返回,接着执行之后的语句;(2)await等到async函数的结果之后,从await之后的语句开始在另外一个线程执行。


<think>我们正在讨论.NET8中Task的用法。Task.NET中异步编程的核心,用于表示异步操作。在.NET8中,Task的使用方式与之前版本基本一致,但可能有一些新的优化和最佳实践。我们将按照以下结构进行说明:1.Task的基本概念2.创建Task3.等待Task4.异步方法(async/await)5.异常处理6.取消任务7.并行任务8.性能优化建议引用我们已有的知识库:[^1]提到了性能优化,可以借鉴其中的思想。[^2]提到了.NET8的集成,说明.NET8是当前推荐版本。[^3]提到了数据库迁移,其中可能涉及异步操作,但这里我们关注Task本身。[^4]提到了一个BLE项目,其中可能有使用Task的示例。下面开始详细说明:</think>### .NET 8 中 Task 使用指南 在 .NET 8 中,`Task` 是异步编程的核心类型,用于表示异步操作。以下是关键使用场景和最佳实践: #### 1. **基本任务创建** ```csharp // 创建并启动任务 Task.Run(() => { Console.WriteLine("后台任务执行中..."); Thread.Sleep(1000); }); // 带返回值的任务 Task<int> calculateTask = Task.Run(() => Enumerable.Range(1, 100).Sum()); ``` #### 2. **异步方法 (async/await)** ```csharp public async Task<string> FetchDataAsync() { using HttpClient client = new(); string result = await client.GetStringAsync("https://api.example.com/data"); return result.ToUpper(); // 自动返回 Task<string> } // 调用示例 var data = await FetchDataAsync(); ``` #### 3. **任务组合** ```csharp // 并行执行多个任务 Task<int> task1 = Task.Run(() => GetInventory()); Task<int> task2 = Task.Run(() => GetSales()); await Task.WhenAll(task1, task2); Console.WriteLine($"库存: {task1.Result}, 销量: {task2.Result}"); // 任意任务完成 Task winner = await Task.WhenAny(downloadTask, timeoutTask); if (winner == downloadTask) { /* 处理数据 */ } ``` #### 4. **取消任务** ```csharp var cts = new CancellationTokenSource(); try { await ProcessDataAsync(cts.Token); } catch (TaskCanceledException) { Console.WriteLine("任务已取消"); } // 在方法内响应取消 async Task ProcessDataAsync(CancellationToken token) { token.ThrowIfCancellationRequested(); await Task.Delay(2000, token); } ``` #### 5. **异常处理** ```csharp try { await TaskThatMightFail(); } catch (HttpRequestException ex) { Console.WriteLine($"网络错误: {ex.Message}"); } // 聚合异常处理 Task failedTask = Task.Run(() => throw new InvalidOperationException("测试异常")); await Task.WhenAll(failedTask.ContinueWith(t => { if (t.IsFaulted) Console.WriteLine(t.Exception!.Flatten().Message); })); ``` #### 6. **性能优化** - 使用 `ValueTask` 减少堆分配: ```csharp public async ValueTask<int> CacheGetAsync(string key) { if (cache.TryGetValue(key, out int value)) return value; value = await LoadFromDbAsync(key); return value; } ``` - 避免 `.Result` 阻塞线程,优先使用 `await` - 使用 `Task.CompletedTask` 返回空任务: ```csharp public Task NoOpAsync() => Task.CompletedTask; ``` #### 7. **高级模式** ```csharp // 任务延续 Task.Run(Step1) .ContinueWith(t => Step2(t.Result), TaskContinuationOptions.OnlyOnRanToCompletion); // 进度报告 var progress = new Progress<int>(percent => Console.WriteLine($"{percent}%")); await ProcessWithProgressAsync(progress); ``` > **最佳实践** > - 始终使用 `async/await` 避免死锁 > - 对 CPU 密集型任务用 `Task.Run` 卸载到线程池 > - 使用 `CancellationToken` 支持协作式取消 > - 避免 `async void`(除事件处理程序外) > - 在库代码中考虑 `ValueTask` 优化性能[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值