C#开发常见面试题二(多线程)

背景

如果面试上位机岗位,多线程被考察的频率很高。

面试题

1.并发并行的区别?异步同步的区别?

并发单核处理器能够同时执行个线程,同一时间只能执行一个,其他线程挂起,通过时间片分配实现。
并行:指两个或更多事件或活动在同一时刻发生,通常与多核处理器相关。
同步:任务需依次执行,等待当前任务完成才能执行下一个。
异步:任务之间不相互等待,可以同时执行多个任务。

2. 什么时间用多线程?什么时间用异步编程?

多线程适用于IO密集型应用,如网络请求、文件操作等。
异步编程适用于计算密集型应用,如视频处理、科学计算等。

3.线程是如何工作的?

线程在内部由一个线程调度器(thread scheduler)管理,一般CLR会把这个任务交给操作系统完成。
单核处理器使用时间切片。多核处理器则是时间切片和并发混合使用。

4.举例说明多线程使用场景?缺点?

使用场景
维持用户界面的响应
有效利用 CPU
并行计算
推测执行(speculative execution)
允许同时处理请求

缺点:程序的复杂度
缺点处理:多线程逻辑使用可重用的类封装,以便于独立的检验和测试。

5.如果程序依赖finally(或是using)块来执行清理工作,例如释放资源或是删除临时文件,就可能会产生问题。如何处理?

如果是自己创建的线程,在线程上调用Join方法。
如果是使用线程池线程,使用事件等待句柄。

6.如何调用线程池?常见的线程池对象?

通过任务并行库(TPL)(Framework 4.0 中加入)
调用ThreadPool.QueueUserWorkItem
通过异步委托
通过BackgroundWorker

常见对象

WCF、Remoting、ASP.NET 和 ASMX 网络服务应用
System.Timers.Timer 和 System.Threading.Timer
.NET Framework 中名字以Async结尾的方法,例如WebClient上的方法,和大部分BeginXXX方法(异步编程模型模式,APM)
PLINQ

7. 最小线程池数量如何起作用?为何延迟创建线程?

需要时,立刻创建最小线程数量的线程,线程数<=min时,增量创建线程。通常min默认处理器数目。
延迟创建原因:了防止短生命周期的任务导致线程数量短暂高峰

8.C#中排他锁有哪些?区别?

lock(locker); Monitor.Enter/Monitor.Exit/Monitor.TryEnter;/Mutex(互斥体)
Mutex可以跨线程使用

9.任务并行(task parallelism)的作用?

调节任务调度
在一个任务中启动另一个任务时建立其父子关系
实现协作取消
等待一组任务,而无需使用信号构造
附加“延续”任务
基于多个前项任务调度延续任务
传递异常给父任务、延续任务和任务的使用方

10.WaitAll和WaitAny的区别?WaitAll和分别等待有什么区别?

WaitAll等待所有任务完成;
WaitAny等待任意任务完成;

WaitAll只会切换一次上下文;

11.Task如何实现取消任务?

CancellationTokenSource定义了Cancel方法。
CancellationToken定义了IsCancellationRequested属性和ThrowIfCancellationRequested方法。

CancellationToken是一个结构体,但是你可以把它当作类来看待。引用原始的CancellationTokenSource。
CancellationToken结构体提供了其它两个有用的成员。
第一个是WaitHandle,返回一个等待句柄,在取消时会对它发信号。
第二个是Register,使你可以注册一个在取消时调用的委托。

CancellationTokenSource定义了Cancel方法
它可以调度一个委托到线程池线程上运行。
它提供了管理工作项的丰富功能(延续、子任务、异常封送等等)。

public class TaskCompletionSource<TResult>
{
  public void SetResult (TResult result);
  public void SetException (Exception exception);
  public void SetCanceled();

  public bool TrySetResult (TResult result);
  public bool TrySetException (Exception exception);
  public bool TrySetCanceled();
  // ...
}

12.C#中async、await关键字

异步方法:用async关键字修饰的方法。
await不会阻塞主线程,await后的主线程代码依然会执行。
异步方法的返回值一般是Task,T是真正的返回值类型,Task。惯例:异步方法的名字以Async结尾;
即使方法没有返回值,也最好把返回值声明为非泛型的Task;
调用泛型方法时,一般在方法前加上await关键字,这样拿到的返回值就是泛型指定的T类型;
异步方法的”传染性“:一个方法如果await调用,则这个方法也必须修改为async;
如果一个方法是异步方法,那么一般在调用这个方法的时候在方法前加await关键字;

13.async方法的缺点?

异步方法会生成一个类,运行效率没有普通方法高;
可能会占用非常多的线程;
用async和await配合来调用普通方法(推荐此方式,运行效率高)

异步暂停的情况
Thread.Sleep()方法,因为它会阻塞调用线程,而要用await Task.Delay()

14.yield return和return的区别?

return:立刻返回

yield return
适用lazy loading
定义一个迭代器块。它允许逐个产生序列的元素,而不是一次性产生整个集合。
当一个方法中包含yield return时,这个方法必须返回一个实现了IEnumerable、IEnumerator或IAsyncEnumerable的类型(取决于是否使用异步迭代器)

yield return 的优势在于,如果GetStrings 方法中的字符串是通过某种计算或I/O操作(如文件读取)获得的,
那么使用yield return可以减少内存占用并提高效率。普通的return则需要一次性创建和返回整个集合。

<think>嗯,用户让我介绍一下C#多线程面试题。首先,我需要确定用户的需求是什么。可能是准备面试,或者学习C#多线程相关知识。用户可能有一定的C#基础,但想深入了解多线程相关的常见问题,以便在面试中应对自如。 接下来,我要回忆常见C#多线程面试题。通常,面试题会涉及基本概念、线程与任务的区别、同步机制、线程池、异步编程等。需要覆盖这些方面,并且给出具体的例子,比如代码示例,这样用户更容易理解。 然后,我需要组织内容结构。分几个主要部分,比如基本概念、常见问题及解析、代码示例、注意事项等。每个部分下再细分问题,比如线程和进程的区别,线程的生命周期,如何创建线程,同步技术,死锁,线程池,async/await,线程安全集合,BackgroundWorker,多线程调试技巧等。 还要注意用户提到的系统级指令,比如数学公式的格式,但这里可能用不上。但需要确保回答结构清晰,符合用户可见层的要求,逐步解答,真实可靠。 需要检查每个知识点的准确性,比如Task和Thread的区别,Task是基于线程池的,更高效。同步机制如lock、Monitor、Mutex、Semaphore的应用场景。死锁产生的条件以及如何避免,比如按顺序获取锁。线程池的优点和使用ThreadPool.QueueUserWorkItem的例子。 异步编程部分要提到async/await关键字,区分IO密集和计算密集型任务。线程安全集合如ConcurrentBag,BlockingCollection。可能还要提到旧版的BackgroundWorker类,虽然现在推荐用async/await,但面试中可能会被问到。 在代码示例部分,要确保语法正确,比如lock的正确使用,避免锁定this或字符串。Monitor的Enter和Exit要配对,使用try-finally。Mutex的命名和跨进程使用。线程池的例子,Task.Run的使用等。 另外,注意事项部分,要强调避免过度线程化,同步的重要性,识别线程安全方法,使用CancellationToken取消任务,以及多线程调试的挑战,比如使用断点和日志。 最后,总结常见考点,帮助用户抓住重点。比如线程同步、Task与Thread的区别、死锁预防、async/await原理、线程池优化等。 需要确保内容全面,但不过于冗长。语言要简洁明了,用中文,避免术语混乱。检查是否有遗漏的重要知识点,比如Parallel类或PLINQ,但可能属于进阶内容,可以简要提及。 总之,整理出结构清晰、覆盖主要考点、附带代码示例和注意事项的回答,帮助用户系统性地准备C#多线程相关的面试问题。</think>以下是一份系统化的C#多线程常见面试题解析,涵盖核心概念与代码示例: --- ### 一、基础概念 1. **线程与进程的区别** - 进程是操作系统分配资源的最小单位,线程是CPU调度的最小单位 - 一个进程包含多个线程,线程共享进程内存空间 2. **多线程的优缺点** - ✅ 优点:提升响应速度、利用多核CPU、异步操作 - ❌ 缺点:调试难度高、线程安全问题、资源竞争 --- ### 、核心面试题解析 #### 1. 如何创建线程? ```csharp // 使用Thread类 Thread t1 = new Thread(new ThreadStart(DoWork)); t1.Start(); // 带参数线程 Thread t2 = new Thread(new ParameterizedThreadStart(DoWorkWithParam)); t2.Start("参数"); ``` #### 2. `Task`与`Thread`的区别 - `Thread`是低级API,直接操作系统线程 - `Task`基于线程池(默认),更高效管理线程资源 - 推荐优先使用`Task` #### 3. 线程同步技术对比 | 机制 | 适用场景 | 示例代码片段 | |---------------|----------------------------------|---------------------------------| | `lock` | 临界区简单同步 | `lock(obj) { ... }` | | `Monitor` | 更细粒度控制 | `Monitor.Enter(obj); try{...} finally{Monitor.Exit(obj);}` | | `Mutex` | 跨进程同步 | `using Mutex mutex = new Mutex(false, "GlobalMutex");` | | `Semaphore` | 控制并发数量 | `SemaphoreSlim sem = new SemaphoreSlim(3);` | #### 4. 死锁的产生与避免 **必要条件**:互斥、持有并等待、不可剥夺、循环等待 **避免方法**: ```csharp // 按固定顺序获取锁 object lock1 = new object(); object lock2 = new object(); void ThreadA() { lock(lock1) { lock(lock2) { ... } } } void ThreadB() { lock(lock1) { // 与ThreadA保持相同顺序 lock(lock2) { ... } } } ``` #### 5. 线程池使用 ```csharp ThreadPool.QueueUserWorkItem(state => { Console.WriteLine($"线程池线程ID: {Thread.CurrentThread.ManagedThreadId}"); }); // 更推荐使用Task.Run Task.Run(() => { // 后台执行代码 }); ``` --- ### 三、高级话题 1. **async/await原理** - 基于状态机实现非阻塞 - 不创建新线程(IO操作),但CPU密集型任务会占用线程池线程 2. **线程安全集合** ```csharp var concurrentBag = new ConcurrentBag<int>(); var blockingCollection = new BlockingCollection<int>(); ``` 3. **取消任务** ```csharp var cts = new CancellationTokenSource(); Task.Run(() => { while(!cts.Token.IsCancellationRequested) { // 工作代码 } }, cts.Token); cts.Cancel(); // 触发取消 ``` --- ### 四、调试技巧 1. 使用`Thread.CurrentThread.ManagedThreadId`跟踪线程 2. 在Visual Studio中使用"Parallel Stacks"窗口 3. 避免`Thread.Sleep()`,改用`Task.Delay()`(异步友好) --- ### 常见考点总结 - 同步机制的选择依据 - `Task`与`Thread`的底层实现差异 - 死锁场景的代码分析 - `async/await`如何避免阻塞UI线程 - 线程池的参数调优(`SetMinThreads`/`SetMaxThreads`) 建议结合具体代码实践加深理解,面试时可准备1-2个实际项目中的多线程应用案例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值