c# async await 理解 结合并行处理

本文通过两个C#代码示例,详细解析了异步编程中await关键字的作用及Parallel.ForEach的使用,阐述了主线程如何在遇到await时非阻塞性地继续执行,以及Task对象前使用await会如何阻塞线程直至异步操作完成。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写两个方法

第一个

List<int> list = new List<int>();
int i= 0;
do
{
    i++;
    list.Add(i);
} while (i< 10);
Console.WriteLine("开始执行时间:" + DateTime.Now.ToString());
Parallel.ForEach(list, async item =>
{
    var result = await Test();
    Console.WriteLine("线程" + result.ToString());
});

第二个

public static async Task<string> Test()
{
    return await Task.Run(() =>
      {
          Thread.Sleep(2000);
          Console.WriteLine("Test()方法里面线程ID: {0}", Thread.CurrentThread.ManagedThreadId);
          Console.WriteLine("执行时间:" + DateTime.Now.ToString());
          return Thread.CurrentThread.ManagedThreadId.ToString();
      });
}

  

 

可以区分来看

Test() 是一个部分

await  Test()又是一部分

这两部分运行的位置不一样,第一部分就跟我们平时调用一样,在当前线程直接执行,第二部分的执行取决于我们await的对象,执行的位置也在await对象内部。

这样子不太好看

主线程碰到await后会立刻返回,以非阻塞的形式执行后面的代码。

在Task对象前面用 await会阻塞线程,直到Task中的异步操作结束。程序才会继续执行。(也就是第二部分里面的r的方法对象是阻塞的,只有运行完才会继续执行)

附上运行图

第一次

第二次

可能觉得看的有点迷茫

我们改一下代码 Console.WriteLine("Test()方法里面线程ID: {0},时间:{1}", Thread.CurrentThread.ManagedThreadId, DateTime.Now.ToString());

第三次执行

发现在执行第二部分的时候,存在不是同步的情况

理论上第二部分是同步的 

这里出现异步的情况是因为并行

我同时执行了10个线程 

然后每个线程都执行第一部分 然后在执行第二部分

如果仅仅只是执行1个线程 那么就是先第一部分 然后第二部分了

 

 

欢迎补充...

 

转载于:https://www.cnblogs.com/sajiao/p/11008642.html

<think>好的,我现在需要帮助用户了解C#asyncawait关键字的用法,并提供示例。首先,我要回顾一下用户提供的引用内容,确保信息准确。根据引用[1],当使用await时,挂起的是直接包含await的异步方法,而不是外部方法。引用[2]提到asyncawait必须搭配使用,await后面接的是正在运行的Task。引用[3]指出asyncawait让异步代码更易读和维护。引用[4]中的示例展示了异步方法的执行流程。 首先,我需要解释asyncawait的基本概念。用户可能想知道为什么需要这两个关键字,以及它们如何简化异步编程。根据引用[3],异步编程传统上使用回调、事件等,但async/await让代码看起来像同步,更容易理解。所以应该先介绍这一点。 接下来是使用方法。需要说明如何声明异步方法,即用async修饰符,并返回Task或Task<T>。根据引用[2],async Task<TResult>是常见的返回类型。这里要强调方法签名中的async和返回类型的重要性。 然后,解释await的作用。根据引用[1],当遇到await时,当前异步方法会被挂起,控制权返回给调用者,直到等待的任务完成。这意味着不会阻塞线程,这在UI或服务应用中很重要。需要举例说明,比如在UI线程中等待网络请求时,不会冻结界面。 示例部分,用户需要看到具体的代码。引用[4]中的示例展示了多个步骤和await的使用。可以创建一个简单的示例,比如模拟下载数据,使用HttpClient或者Task.Delay来演示异步操作。例如,一个DownloadDataAsync方法,内部使用await等待网络请求,然后在按钮点击事件中调用它,并同样使用await,确保UI响应。 还要注意异常处理和配置任务,比如ConfigureAwait(false)的作用,避免死锁。这部分可能在高级用法中提到,但用户可能也需要知道。 用户可能的问题包括:如何处理返回值?是否所有方法都可以用async?是否需要避免async void?根据引用[2],async void应该避免,除了事件处理程序。需要提醒用户这一点。 最后,生成相关问题,帮助用户进一步学习。比如性能优化、与多线程的区别、错误处理等。这些问题应该基于常见疑惑点。 现在需要组织这些信息,结构清晰,分步骤说明,并附上代码示例。确保使用正确的中文术语,避免技术术语混淆。同时,检查LaTeX格式是否正确,但根据用户的问题,可能不需要数学公式,但系统指令要求行内数学表达式用$...$,但这里可能不涉及,所以可能不需要。但如果有变量或代码中的符号,可能需要处理。例如,Task<TResult>中的泛型可能需要转义,但代码块中会正确显示。 总结步骤: 1. 基本概念:为什么使用async/await,与传统方法的对比。 2. 使用方法:声明异步方法,返回类型,await的使用位置。 3. 示例代码:简单的异步方法,调用示例。 4. 注意事项:避免async void,ConfigureAwait,异常处理。 5. 相关问题:引导深入学习。 需要确保引用标注正确,比如在提到挂起方法时引用[^1],搭配使用时引用[^2],便捷方法引用[^3],示例结构引用[^4]。 现在开始撰写回答,确保符合所有系统级指令,特别是中文回答、正确引用标注,以及相关问题生成。</think>### C#asyncawait关键字的使用方法及示例 #### **一、基本概念** 在C#中,`async`和`await`是用于简化异步编程的关键字。它们允许开发者以类似同步代码的方式编写异步操作,提升代码可读性和维护性[^3]。例如,在等待网络请求或文件读写时,异步方法不会阻塞当前线程,从而避免界面冻结或服务器资源浪费。 --- #### **二、使用方法** 1. **声明异步方法** 使用`async`修饰符标记方法,并指定返回类型为`Task`或`Task<T>`(若需返回值)。例如: ```csharp public async Task<int> GetDataAsync() { ... } ``` 2. **使用`await`等待异步操作** 在异步方法内部,通过`await`等待一个返回`Task`的操作。此时,当前方法会挂起,控制权返回给调用者,直到任务完成[^1]。 ```csharp int result = await SomeAsyncMethod(); ``` 3. **避免`async void`** 除非是事件处理程序,否则应始终返回`Task`或`Task<T>`,以正确处理异常和任务状态。 --- #### **三、示例代码** 以下示例模拟从网络下载数据: ```csharp public class Demo { // 异步方法声明 public async Task<string> DownloadDataAsync(string url) { using (var client = new HttpClient()) { // 使用await等待HTTP请求 string data = await client.GetStringAsync(url); return data.ToUpper(); } } // 调用异步方法(如按钮点击事件) public async void Button_Click(object sender, EventArgs e) { try { string result = await DownloadDataAsync("https://example.com"); Console.WriteLine(result); } catch (Exception ex) { Console.WriteLine($"Error: {ex.Message}"); } } } ``` **执行流程** 1. 调用`DownloadDataAsync`时,遇到`await`会挂起当前方法,释放控制权。 2. HTTP请求完成后,恢复执行并返回结果。 3. 若发生异常,通过`try-catch`捕获处理。 --- #### **四、注意事项** 1. **配置上下文** 在非UI场景(如后台服务)中,使用`ConfigureAwait(false)`避免不必要的上下文切换: ```csharp var data = await SomeTask().ConfigureAwait(false); ``` 2. **并行任务优化** 使用`Task.WhenAll`并行执行多个异步操作: ```csharp var tasks = new[] { Task1(), Task2(), Task3() }; await Task.WhenAll(tasks); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值