哪些 .NET 4.5(或更早版本)更高级别的构造使线程更容易? [英] What .NET 4.5 (or earlier) higher-level constructs make Threading easier?

查看:23
本文介绍了哪些 .NET 4.5(或更早版本)更高级别的构造使线程更容易?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

委托是使 .NET 中的线程更容易的一些对象参考.它们可用于异步调用方法.框架 4.5(或更早版本)中还有哪些其他对象可以使线程的使用更容易或更不容易出错?

Delegates are a few of the objects that make threading easier in .NET reference. They can be used to asynchronously invoke a method. What other objects exist in framework 4.5 (or earlier) that make the use of threads easier or less error prone?

还有哪些抽象使并发和多线程更容易?

What are the other abstractions make concurrency and multithreading easier?

注意:这个问题更新了这个.

Note: This question updates this.

推荐答案

我倾向于回答很多与多线程相关的问题,而且我经常看到以各种不同的方式提出相同的基本问题.我将介绍多年来我遇到的最常见的问题,并解释新技术如何使解决这些问题变得更容易.

I tend to answer a lot of questions related to multithreading and I often see the same basic question asked in various different ways. I will present the most common problems as I have seen them over the years and explain how the newer technologies have made solving these problems easier.

结束循环变量

这不是线程特有的问题,但是线程的使用肯定会放大问题.C# 5.0 通过为每次迭代创建一个新变量来修复 foreach 循环的这个问题.您将不再需要为 lambda 表达式闭包创建特殊变量.不幸的是,for 循环仍然需要使用特殊的捕获变量来处理.

This is not a problem specific to threading, but the use of threading definitely magnifies the problem. C# 5.0 fixes this problem for the foreach loop by creating a new variable for each iteration. You will no longer have to create a special variable for lambda expression closures. Unfortunately, the for loop will still need to be handle with a special capturing variable.

等待异步任务完成

.NET 4.0 引入了 CountdownEvent 类,它封装了许多等待许多任务完成所需的逻辑.大多数初级开发人员使用Thread.Join 调用或单个WaitHandle.WaitAll 调用.这两者都有可扩展性问题.旧模式是使用单个 ManualResetEvent 并在计数器达到零时发出信号.计数器是使用 Interlocked 类更新的.CountdownEvent 使这种模式更加容易.请记住将您的主线程也视为一个 worker,以避免在所有 worker 都排队之前一个 worker 完成时可能发生的微妙竞争条件.

.NET 4.0 introduced the CountdownEvent class which encapsulates a lot of the logic required to wait for the completion of many tasks. Most junior developers used Thread.Join calls or a single WaitHandle.WaitAll call. Both of these have scalability problems. The old pattern was to use a single ManualResetEvent and signal it when a counter reached zero. The counter was updated using the Interlocked class. CountdownEvent makes this pattern much easier. Just remember to treat your main as a worker as well to avoid that subtle race condition that can occur if one worker finishes before all workers have been queued.

.NET 4.0 还引入了 Task 类,该类可以通过 TaskCreationOptions.AttachedToParent 链接子任务.如果您对父级调用 Task.Wait,它将等待所有子任务也完成.

.NET 4.0 also introduced the Task class which can have child tasks chained off of it via TaskCreationOptions.AttachedToParent. If you call Task.Wait on a parent it will wait for all child tasks to complete as well.

生产者-消费者

.NET 4.0 引入了 BlockingCollection 类,它的作用类似于普通队列,但它可以在集合为空时阻塞.您可以通过调用Add 将对象排队,并通过调用Take 将对象出队.Take 块,直到项目可用.这大大简化了生产者-消费者逻辑.过去,开发人员试图编写自己的阻塞队列类.但是,如果你不知道你在做什么,那么你真的可以把它搞砸……糟糕.事实上,长期以来,微软在 MSDN 文档中有一个阻塞队列示例,它本身就被严重破坏了.幸运的是,它已被删除.

.NET 4.0 introduced the BlockingCollection class which acts like a normal queue except that it can block when the collection is empty. You can queue an object by calling Add and dequeue an object by calling Take. Take blocks until an item is available. This simplifies producer-consumer logic considerably. It used to be the case that developers were trying to write their own blocking queue class. But, if you do not know what you are doing then you can really screw it up...bad. In fact, for the longest time Microsoft had a blocking queue example in the MSDN documentation that was itself badly broken. Fortunately, it has since been removed.

使用工作线程进度更新 UI

BackgroundWorker 的引入使新手开发人员更容易从 WinForm 应用程序中分离出后台任务.主要好处是您可以从 DoWork 事件处理程序中调用 ReportProgress,并且 ProgressChanged 事件处理程序将自动编组到 UI 线程上.当然,任何在 SO 上跟踪我的答案的人都知道我对将封送操作(通过 Invoke 等)作为使用简单进度信息更新 UI 的解决方案的感受.我一直在抨击它,因为它通常是一种糟糕的方法.BackgroundWorker 仍然强制开发人员进入推送模型(通过后台的编组操作),但至少它在幕后完成了所有这些.

The introduction of BackgroundWorker made spinning off a background task from a WinForm application a lot easier for novice developers. The main benefit is that you can call ReportProgress from within the DoWork event handler and the ProgressChanged event handlers will be automatically marshaled onto the UI thread. Of course, anyone that tracks my answers on SO knows how I feel about marshaling operations (via Invoke or the like) as a solution for updating the UI with simple progress information. I rip on it all the time because it is generally a terrible approach. BackgroundWorker still forces the developer into a push model (via marshaling operations in the background), but at least it does all of this behind the scenes.

Invoke 的不优雅

我们都知道一个 UI 元素只能从 UI 线程访问.这通常意味着开发人员必须通过 ISynchronizeInvokeDispatcherObjectSynchronizationContext 使用封送操作将控制权转移回 UI 线程.但让我们面对现实吧.这些编组操作看起来很丑陋.Task.ContinueWith 使这更优雅一些,但真正的荣耀归于 await 作为 C# 5 新异步编程模型的一部分.await 可用于等待 Task 完成,这样流控制在任务运行时暂时中断,然后在右侧的那个位置返回同步上下文.没有什么比使用 await 替代所有那些 Invoke 调用更优雅和令人满意的了.

We all know that a UI element can only be accessed from the UI thread. This generally meant that a developer had to use marshaling operations via ISynchronizeInvoke, DispatcherObject, or SynchronizationContext to transfer control back to the UI thread. But lets face it. These marshaling operations look ugly. Task.ContinueWith made this a little more elegant, but the real glory goes to await as part of C# 5's new asynchronous programming model. await can be used to wait for a Task to complete in such a manner that flow control is temporarily interrupted while the task is running and then returned at that very spot in the right synchronization context. There is nothing more elegant and satisfying than using await as a replacement for all those Invoke calls.

并行编程

我经常看到一些问题,询问事情如何并行发生.旧的方法是创建几个线程或使用 ThreadPool..NET 4.0 使用了 TPL 和 PLINQ.Parallel 类是让循环的迭代并行进行的好方法.而 PLINQ 的 AsParallel 是普通 LINQ 的另一面.这些新的 TPL 特性极大地简化了这类多线程编程.

I often see questions asking how things can happen in parallel. The old way was to create a few threads or use the ThreadPool. .NET 4.0 gave use the TPL and PLINQ. The Parallel class is a great way to get the iterations of a loop going in parallel. And PLINQ's AsParallel is a different side of the same coin for plain old LINQ. These new TPL features greatly simplify this category of multithreaded programming.

.NET 4.5 引入了 TPL 数据流库.它旨在使原本复杂的并行编程问题变得优雅.它将类抽象为块.它们可以是目标块或源块.数据可以从一个块流到另一个块.有许多不同的块,包括 BufferBlockBroadcastBlockActionBlock 等,它们都做不同的事情.当然,整个库将针对新的 asyncawait 关键字进行优化.这是一组令人兴奋的新课程,我认为它会慢慢流行起来.

.NET 4.5 introduces the TPL Data Flow library. It is intended to make elegant an otherwise complex parallel programming problem. It abstracts classes into blocks. They can be target blocks or source blocks. Data can flow from one block to another. There are many different blocks including BufferBlock<T>, BroadcastBlock<T>, ActionBlock<T>, etc. that all do different things. And, of course, the whole library will be optimized for use with the new async and await keywords. It is an exciting new set of classes that I think will slowly catch on.

正常终止

如何让线程停止?我经常看到这个问题.最简单的方法是调用 Thread.Abort,但我们都知道这样做的危险......我希望如此.有许多不同的方法可以安全地做到这一点..NET 4.0 通过CancellationTokenCancellationTokenSource 引入了一个更统一的概念,称为取消.后台任务可以轮询 IsCancellationRequested 或在安全点调用 ThrowIfCancellationRequested 以优雅地中断他们正在做的任何工作.其他线程可以调用Cancel来请求取消.

How do you get a thread to stop? I see this question a lot. The easiest way is to call Thread.Abort, but we all know the perils of doing this...I hope. There are many different ways to do this safely. .NET 4.0 introduced a more unified concept called cancellation via CancellationToken and CancellationTokenSource. Background tasks can poll IsCancellationRequested or just call ThrowIfCancellationRequested at safe points to gracefully interrupt whatever work they were doing. Other threads can call Cancel to request cancellation.

这篇关于哪些 .NET 4.5(或更早版本)更高级别的构造使线程更容易?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆