C# async/await深度解析:面试题+原理与区别

需积分: 0 0 下载量 41 浏览量 更新于2024-06-23 收藏 75KB DOCX 举报
C# 19道面试题涉及了多个关键知识点,包括异步编程模型、Task和线程的差异以及yield的关键作用。以下是详细解析: 1. **Async函数的编译方式与Task状态机** C#的`async`关键字用于标记函数为异步,它实际上编译成了状态机模型。编译过程如下: - 异步函数被转换为包含状态机逻辑的隐藏类,其中包含局部变量的闭包。 - `await`关键字被展开为状态转移,每个await对应一个状态号。 - 状态机通过`MoveNext`方法按顺序执行,当遇到await时,暂停当前线程,切换到回调函数处理异步任务,再继续执行。 - 异步操作可能在线程池、单独线程或主线程上执行,`await`与`GetResult()`的主要区别在于线程管理和阻塞行为。 2. **Task状态机的实现与工作机制** Task是.NET中的一个重要概念,它代表一个异步操作的结果。Task状态机基于CPS(Continuation Passing Style)工作,包含以下步骤: - 创建一个隐藏的状态机类,存储局部变量的闭包。 - await表达式被转换为状态转移,每一步对应一个状态。 - MoveNext方法根据状态执行相应操作,处理线程调度和异常情况。 - 当await的Task在其他线程完成时,主线程会被释放,等待回调。 3. **await的作用和原理与GetResult()的对比** `await`通过`Task.GetAwaiter().UnsafeOnCompleted`将任务的完成通知状态机,切换到下个状态。`GetResult()`则是在当前线程阻塞等待任务完成,不释放主线程。Task不一定总在新线程上执行,这时两者仅影响是否创建状态机,而非线程调度。 4. **Task与Thread的区别** Task和Thread都可以用来实现多线程,但Task更现代且功能更强大: - Task引入于.NET 4.5,支持async/await编程模型,可以利用线程池,灵活选择执行策略。 - 在UI编程中,Task能自动回到UI线程,简化并发管理。 - Task提供了更多的API来协调和管理多个任务,推荐使用Task进行异步编程。 5. **yield的作用与实现** `yield`配合`IEnumerable<T>`用于生成器,允许函数多次返回值(非递归)。它与async/await类似,也是一种隐式的状态机。不使用yield时,需显式实现`GetEnumerator<T>`方法,确保代码可重入。与C++/Java/ES6中的yield不同,C#的yield更注重简洁和易用性。 这些知识点涵盖了C#中的核心异步编程概念,面试时考察了应聘者对现代C#特性及其实际应用的理解。