代表们有一些,使在.NET线程更容易的对象的引用 。 它们可用于异步调用的方法。 在框架4.5(或更早),使线程的使用更容易或更不容易出错的有哪些其他的对象?
什么是其他抽象使并发和多线程更容易?
注意:这个问题将更新此 。
代表们有一些,使在.NET线程更容易的对象的引用 。 它们可用于异步调用的方法。 在框架4.5(或更早),使线程的使用更容易或更不容易出错的有哪些其他的对象?
什么是其他抽象使并发和多线程更容易?
注意:这个问题将更新此 。
我倾向于回答很多关于多线程的问题,我经常看到各种不同的方式问同样的基本问题。 我将介绍最常见的问题,因为我看到他们多年来和解释新技术如何做出更容易解决这些问题。
关闭了循环变量
这是不特定线程的问题,而是使用线程的绝对放大的问题。 C#5.0修复了这个问题的foreach
通过创建每个迭代一个新的可变环。 您将不再需要创建lambda表达式封闭的特殊变量。 不幸的是, for
循环仍然需要使用特殊的捕捉变量处理。
等待异步任务完成
.NET 4.0中引入的CountdownEvent
类封装了很多等待的许多任务的完成所需要的逻辑。 最初级的开发人员使用Thread.Join
来电或单个WaitHandle.WaitAll
电话。 这些都具有可伸缩性问题。 旧的模式是使用单一ManualResetEvent
和信号它当计数器达到零。 该计数器使用更新后的Interlocked
类。 CountdownEvent
使这种模式更加容易。 不过,别忘了把你的主要的工人,以及避免,如果所有工人已经排队前一个工人完成可能发生微妙的竞争条件。
.NET 4.0还引入了Task
,可以通过具有链连接它的子任务类TaskCreationOptions.AttachedToParent
。 如果你调用Task.Wait
上的父,将等待所有子任务完成为好。
生产者-消费者
.NET 4.0引入的BlockingCollection
其作用像不同的是当集合为空它可以阻止一个正常队列类。 你可以通过调用排队对象Add
,并通过调用出队的对象Take
。 Take
块直至产品可用。 这大大简化了生产者 - 消费者的逻辑。 它曾经是开发商试图写自己的阻塞队列类的情况。 但是,如果你不知道你在做什么,然后你才能真正搞砸了......坏。 事实上,时间最长的有微软MSDN文档这是本身严重打破了一个阻塞队列的例子。 幸运的是,它已被删除。
与工作者线程进度更新UI
引进BackgroundWorker
实现了从WinForm应用程序的开发新手容易得多分拆后台任务。 主要的好处是,你可以调用ReportProgress
从内DoWork
事件处理程序和ProgressChanged
事件处理程序将被自动编组到UI线程。 当然,任何人,跟踪上,所以我的答案,知道我是怎么想编组操作(通过Invoke
等)作为更新与简单的进度信息的UI解决方案。 我就可以撕裂一切的时候,因为它通常是一个可怕的做法。 BackgroundWorker
仍然迫使开发商为推模式(通过在后台编组操作),但至少它确实这一切的幕后。
调用的inelegance
我们都知道,一个UI元素只能从UI线程访问。 这通常意味着开发者必须通过使用编组作业ISynchronizeInvoke
, DispatcherObject
,或者SynchronizationContext
转移回控制到UI线程。 但是让我们面对它。 这些编组操作看起来很丑陋。 Task.ContinueWith
做出这个多了几分优雅,但真正的荣耀去await
为C#5的新异步编程模型的一部分。 await
可用于等待一个Task
以在流动的任务正在运行时,控制被暂时中断,然后在合适的同步上下文非常点返回这样的方式完成。 没有什么更优雅,比使用满意await
作为所有这些替代Invoke
呼叫。
并行编程
我经常看到询问如何事情可以并行发生的问题。 旧的方式是创建一个线程数或使用ThreadPool
。 .NET 4.0给使用TPL和PLINQ。 该Parallel
类是一个伟大的方式得到一个循环并行去的迭代。 和PLINQ的AsParallel
是同一枚硬币的普通老LINQ的不同侧面。 这些新功能TPL大大简化这一类的多线程编程的。
.NET 4.5引入的TPL数据流库。 它的目的是让优雅的其他复杂的并行编程的问题。 它通过抽象类成块。 它们可以是目标块或源块。 数据可以从一个块流到另一个。 有许多不同的块,包括BufferBlock<T>
BroadcastBlock<T>
ActionBlock<T>
等所有做不同的事情。 而且,当然,整个库将被用于新的应用进行了优化async
和await
关键字。 这是一个令人兴奋的新的一组类,我觉得会慢慢流行起来。
正常终止
你如何让一个线程停止? 我看到这个问题很多。 最简单的方法是调用Thread.Abort
,但我们都知道这样做的危险...我希望。 有许多不同的方法来安全地做到这一点。 .NET 4.0通过引入一个更加统一的概念,称为消除CancellationToken
和CancellationTokenSource
。 后台任务可以查询IsCancellationRequested
或只是调用ThrowIfCancellationRequested
在安全点,摆好中断他们正在做力所能及的工作。 其他线程可以调用Cancel
请求取消。
那么让我们来看看这里:
ThreadPool
类-有点老了,但仍然可靠简单的生产者-消费者模式。 BackgoundWorker
(.NET 2.0 +) -另一个老学校建设,用于在GUI应用程序的后台执行任务提供有用的功能。 Timer
秒-在使用后台线程指定的时间间隔执行的代码是有用的。 Task
类(.NET 4.0 +) -线程是在底层的线程池中运行,并提供了许多有用的功能,如异常编组和调度抽象。 有用的所谓“任务并行”的格局。 Parallel.For
, Parallel.ForEach
(.NET 4.0+) -好为在一组并行数据的执行相同的操作。 有用的所谓“数据并行”的格局。 Parallel.Invoke
(.NET 4.0 +) -通过进一步的抽象Task
秒。 简单地触发关的代码数块(方法,lambda表达式)并联。 毫无疑问,获得与新交手TPL数据流库(包含在.NET 4.5)会给你在并行开发方面最大的提升。
如果你是认真的高度并行的应用程序,花一两天与数据流熟悉自己。 这是认真做好。
该Task
和Task<T>
但他们已经在这里以来.NET 4 async
不一定与线程工作,看到从ØredevJon的视频进行了很好的解释。