如果面试上位机岗位,多线程被考察的频率很高。
并发:单核处理器能够同时执行个线程,同一时间只能执行一个,其他线程挂起,通过时间片分配实现。
并行:指两个或更多事件或活动在同一时刻发生,通常与多核处理器相关。
同步:任务需依次执行,等待当前任务完成才能执行下一个。
异步:任务之间不相互等待,可以同时执行多个任务。
多线程适用于IO密集型应用,如网络请求、文件操作等。
异步编程适用于计算密集型应用,如视频处理、科学计算等。
线程在内部由一个线程调度器(thread scheduler)管理,一般CLR会把这个任务交给操作系统完成。
单核处理器使用时间切片。多核处理器则是时间切片和并发混合使用。
使用场景
维持用户界面的响应
有效利用 CPU
并行计算
推测执行(speculative execution)
允许同时处理请求
缺点:程序的复杂度
缺点处理:多线程逻辑使用可重用的类封装,以便于独立的检验和测试。
如果是自己创建的线程,在线程上调用Join方法。
如果是使用线程池线程,使用事件等待句柄。
通过任务并行库(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
需要时,立刻创建最小线程数量的线程,线程数<=min时,增量创建线程。通常min默认处理器数目。
延迟创建原因:了防止短生命周期的任务导致线程数量短暂高峰
lock(locker); Monitor.Enter/Monitor.Exit/Monitor.TryEnter;/Mutex(互斥体)
Mutex可以跨线程使用
调节任务调度
在一个任务中启动另一个任务时建立其父子关系
实现协作取消
等待一组任务,而无需使用信号构造
附加“延续”任务
基于多个前项任务调度延续任务
传递异常给父任务、延续任务和任务的使用方
WaitAll等待所有任务完成;
WaitAny等待任意任务完成;
WaitAll只会切换一次上下文;
CancellationTokenSource定义了Cancel方法。
CancellationToken定义了IsCancellationRequested属性和ThrowIfCancellationRequested方法。
CancellationToken是一个结构体,但是你可以把它当作类来看待。引用原始的CancellationTokenSource。
CancellationToken结构体提供了其它两个有用的成员。
第一个是WaitHandle,返回一个等待句柄,在取消时会对它发信号。
第二个是Register,使你可以注册一个在取消时调用的委托。
CancellationTokenSource定义了Cancel方法
它可以调度一个委托到线程池线程上运行。
它提供了管理工作项的丰富功能(延续、子任务、异常封送等等)。
public class TaskCompletionSource
{
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();
// ...
}
异步方法:用async关键字修饰的方法。
await不会阻塞主线程,await后的主线程代码依然会执行。
异步方法的返回值一般是Task,T是真正的返回值类型,Task。惯例:异步方法的名字以Async结尾;
即使方法没有返回值,也最好把返回值声明为非泛型的Task;
调用泛型方法时,一般在方法前加上await关键字,这样拿到的返回值就是泛型指定的T类型;
异步方法的”传染性“:一个方法如果await调用,则这个方法也必须修改为async;
如果一个方法是异步方法,那么一般在调用这个方法的时候在方法前加await关键字;
异步方法会生成一个类,运行效率没有普通方法高;
可能会占用非常多的线程;
用async和await配合来调用普通方法(推荐此方式,运行效率高)
异步暂停的情况
Thread.Sleep()方法,因为它会阻塞调用线程,而要用await Task.Delay()
return:立刻返回
yield return
适用lazy loading
定义一个迭代器块。它允许逐个产生序列的元素,而不是一次性产生整个集合。
当一个方法中包含yield return时,这个方法必须返回一个实现了IEnumerable、IEnumerator或IAsyncEnumerable的类型(取决于是否使用异步迭代器)
yield return 的优势在于,如果GetStrings 方法中的字符串是通过某种计算或I/O操作(如文件读取)获得的,
那么使用yield return可以减少内存占用并提高效率。普通的return则需要一次性创建和返回整个集合。