博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
线程池threadpool_ThreadPool:多线程性能
阅读量:2531 次
发布时间:2019-05-11

本文共 8111 字,大约阅读时间需要 27 分钟。

线程池threadpool

介绍 (Introduction)

随着芯片制造商致力于通过增加时钟速度来增加处理器内核,开发人员需要利用现代CPU的功能。 我们做到这一点的方法之一是在软件中实现并行算法。

One recent task I needed to perform at home was to find and document large files in certain folders.  I do a back up regularly of documents and source code, and large binaries in those folders can cause overflow on the media I use for storage.  So I wanted a program that could scan through all the files in the folder and build a list of files over a certain size.  I thought this would be a good opportunity to use some multithreading and see how the performance was improved.

我在家中需要执行的一项最新任务是在某些文件夹中查找并记录大文件。 我会定期备份文档和源代码,这些文件夹中的大型二进制文件可能会导致我用于存储的介质溢出。 因此,我想要一个程序,该程序可以扫描文件夹中的所有文件并构建一定大小的文件列表。 我认为这是使用一些多线程并查看性能如何提高的好机会。

In terms of parallel processing, .NET developers have several choices.  BackgroundWorker objects are useful for performing lengthy calculations out of the UI thread so that the UI can remain responsive.  You can create your own threads, just by instantiating new Thread objects with delegates to the routines you wish to call.  You can also use the built in .  

在并行处理方面,.NET开发人员有多种选择。 BackgroundWorker对象可用于在UI线程外执行冗长的计算,以便UI可以保持响应状态。 您只需创建带有要调用例程的委托的新Thread对象,即可创建自己的线程。 您还可以使用内置的 。

If you want an aggressively multithreaded application, the ThreadPool object is ideal.  It is designed so that you can queue work items, and as worker threads become available to the pool, the threads will execute the items you queued.  It’s convenient as the framework handles the business of queuing and signaling the threads to start.  

如果您想要一个积极的多线程应用程序,则ThreadPool对象是理想的。 它的设计使您可以对工作项目进行排队,并且当工作线程可用于池时,线程将执行您排队的项目。 由于该框架处理排队和发信号通知线程启动的业务,因此很方便。

实作
(Implementation
)

In terms of design, I took the easy way out.  I thought I would create a new work item for each folder and dump it in the queue.  I will use a ManualResetEvent object for the worker threads to signal that they are finished.  The ThreadPool does not have an easy built in way to determine the state of individual work items.

在设计方面,我采取了简单的方法。 我以为我会为每个文件夹创建一个新的工作项并将其转储到队列中。 我将为工作线程使用ManualResetEvent对象,以指示它们已完成。 ThreadPool没有简单的内置方法来确定单个工作项的状态。

I have a simple class that saves thread state information and is passed into the work item.

我有一个简单的类,用于保存线程状态信息并传递到工作项中。

Private Class ThreadState	Private mDirInfo As DirectoryInfo	Public Property DirInfo As DirectoryInfo		Get			Return mDirInfo		End Get		Set(ByVal value As DirectoryInfo)			mDirInfo = value		End Set	End Property	'Sum of size of all files in this directory (non-recursive.)	Private mDirectorySize As Long	Public Property DirectorySize As Long		Get			Return mDirectorySize		End Get		Set(ByVal value As Long)			mDirectorySize = value		End Set	End Property	Public Sub New(ByVal DirInfo As DirectoryInfo)		Me.DirInfo = DirInfo	End SubEnd Class

Here are some form level declarations which will be explained as we proceed.

这是一些表单级别的声明,我们将在后面进行解释。

'Track files which match the criteriaPrivate FileList As New List(Of FileInfo)'Keep track of number of threads still unfinishedPrivate mNumActiveThreads As Integer'Allow worker threads to signal back to main thread via waithandle.Private mEv As New ManualResetEvent(False)'This is just a handy list to maintain all the directory size information that is gathered.'ThreadState objects are passed into the procedure used by the individual threads.Private ThreadStateList As New List(Of ThreadState)

The call to QueueUserWorkItem takes a WaitCallback parameter, which is a delegate to the subroutine that you want the work item to execute.  The last parameter is an object through which I use to pass the ThreadState object to the subroutine.  So that we know when the ThreadPool is finished processing the queue, we have a form level counter that gets decremented each time a thread finishes.  When the counter is equal to zero, we will call .Set on the ManualResetEvent.  The calling thread will call the WaitOne method on the reset event object, which will block until .Set is called by the worker thread.

对QueueUserWorkItem的调用采用WaitCallback参数,该参数是您希望工作项执行的子例程的委托。 最后一个参数是我用来将ThreadState对象传递给子例程的对象。 因此,当我们知道ThreadPool完成队列处理时,我们就有一个窗体级别计数器,该计数器在每次线程完成时都会递减。 当计数器等于零时,我们将在ManualResetEvent上调用.Set。 调用线程将在reset事件对象上调用WaitOne方法,该方法将阻塞直到工作线程调用.Set为止。

''' ''' This is the main routine that adds each directory as a ''' new threadpool work item.''' ''' ''' 
Public Sub ScanAllFilesMultithreaded(ByVal StartFolder As Object) FolderSize = 0 NumFiles = 0 mEv.Reset() Dim di As New DirectoryInfo(CStr(StartFolder)) Dim DirInfoList As New List(Of DirectoryInfo) GetDirectories(di, DirInfoList) sw = Stopwatch.StartNew mNumActiveThreads = DirInfoList.Count For Each di In DirInfoList AddWorkItem(di) Next 'WaitOne blocks until Set is called on the object in the 'worker thread. mEv.WaitOne() sw.Stop()End Sub''' ''' This adds items to the ThreadState list ''' and adds new work items to the thread pool, all''' based on the directoryinfo object that is passed in.''' ''' '''
Private Sub AddWorkItem(ByVal di As DirectoryInfo) 'Dim Ev As New ManualResetEvent(False) Dim ts As New ThreadState(di) 'EventList.Add(Ev) ThreadStateList.Add(ts) Threading.ThreadPool.QueueUserWorkItem( _ New WaitCallback(AddressOf ScanFiles), ts)End Sub

The code that is called by each work item is in the ScanFiles subroutine.  Notice the use of Interlock.Add and Interlock.Increment.  The provides these thread-safe methods that ensure that only one thread is manipulating the variable at any one time.  Similarly, the FileList.Add method is wrapped in a SyncLock block.   restricts the access to the enclosed variables and code by just one thread at a time.  It is recommended that you don't overuse it.  If large blocks of code are restricted this way, then you are creating a bottleneck for your multithreading.

每个工作项调用的代码在ScanFiles子例程中。 注意使用Interlock.Add和Interlock.Increment。 提供了这些线程安全的方法,可确保在任何时候只有一个线程在操作变量。 同样,FileList.Add方法包装在SyncLock块中。 一次只能限制一个线程对封闭变量和代码的访问。 建议您不要过度使用它。 如果以这种方式限制了大块代码,那么您将为多线程创建瓶颈。

''' ''' This is the procedure called by the thread pool work items.  ''' See AddWorkItem for how this is set up.''' ''' ''' 
Private Sub ScanFiles(ByVal state As Object) Dim TS As ThreadState = CType(state, ThreadState) Try Dim FInfo As FileInfo For Each FInfo In TS.DirInfo.GetFiles 'Since this routine can run simultaneously 'in different threads, it is important to use 'the Interlocked Increment and Add methods to ensure 'that the form level variables are thread safe and 'not subject to race conditions. Interlocked.Increment(NumFiles) Interlocked.Add(TS.DirectorySize, FInfo.Length) If FInfo.Length > Limit Then 'SyncLock ensures that only this thread 'can access the filelist during this Add SyncLock so FileList.Add(FInfo) End SyncLock End If Next Interlocked.Add(FolderSize, TS.DirectorySize) Catch ex As Exception Debug.WriteLine(ex) Finally 'When mNumActiveThreads reaches 0, all the workers are finished. If Interlocked.Decrement(mNumActiveThreads) = 0 Then mEv.Set() End If End TryEnd Sub

测试与结果
(Testing and Results
)

我设置了秒表对象并实现了一个单线程方法,该方法执行相同的任务,并以相同的方式对其进行计时。

There are definitely large improvements in performance on my quad core system when using multithreading.  Results are consistently around 30%-40% of the time taken to scan in a single thread.  This was better than I expected, as I was thinking that the process of doing a single directory per thread may be less efficient because of extra overhead.  But the ThreadPool does a pretty good job of making your multithreading as efficient as it can be.

使用多线程时,我的四核系统的性能肯定有很大的提高。 结果始终是在单个线程中扫描时间的30%-40%左右。 这比我预期的要好,因为我认为每个线程执行单个目录的过程可能会因为额外的开销而效率较低。 但是ThreadPool在使多线程尽可能高效方面做得很好。

First run

结论
(Conclusion
)

The ThreadPool class is a must-have tool for your kit if you have a large number of IO operations that need to happen asynchronously, or if you can spread calculations out in multiple chunks.  The full source code for the test project is here:

如果您有大量需要异步执行的IO操作,或者可以将计算分散为多个块,则ThreadPool类是工具包的必备工具。 测试项目的完整源代码在这里:

FileSizes Example Project Download
FileSizes示例项目下载

It was written in Visual Studio 2005.

它是用Visual Studio 2005编写的。

翻译自:

线程池threadpool

转载地址:http://mgqzd.baihongyu.com/

你可能感兴趣的文章
Android dex分包方案
查看>>
ThreadLocal为什么要用WeakReference
查看>>
删除本地文件
查看>>
FOC实现概述
查看>>
base64编码的图片字节流存入html页面中的显示
查看>>
这个大学时代的博客不在维护了,请移步到我的新博客
查看>>
GUI学习之二十一——QSlider、QScroll、QDial学习总结
查看>>
nginx反向代理docker registry报”blob upload unknown"解决办法
查看>>
gethostbyname与sockaddr_in的完美组合
查看>>
kibana的query string syntax 笔记
查看>>
旋转变换(一)旋转矩阵
查看>>
thinkphp3.2.3 bug集锦
查看>>
[BZOJ 4010] 菜肴制作
查看>>
C# 创建 读取 更新 XML文件
查看>>
KD树
查看>>
VsVim - Shortcut Key (快捷键)
查看>>
C++练习 | 模板与泛式编程练习(1)
查看>>
HDU5447 Good Numbers
查看>>
08.CXF发布WebService(Java项目)
查看>>
java-集合框架
查看>>