我需要帮助创建一个TaskScheduler来防止线程超载

时间:2016-05-06 22:41:23

标签: vb.net multithreading task taskscheduler

我想将工作人员添加到队列中,但只有前N个工作程序并行处理。我找到的所有样品都在C#中。

这对程序员来说可能很简单,但我不是一个。我对VB有足够的了解,可以编写简单的程序。

但我的第一个应用程序运行良好,直到它突然达到100%的CPU然后崩溃。请帮助(是的,我在发布此内容之前浪费了5个小时的工作时间...)

更多上下文:在具有超过100万个目录/子目录的文件服务器上执行目录结构,文件和权限的递归清单。

流程连续运行,但需要数月才能完成。管理层已经在我脖子上呼吸。当我尝试使用任务时,它会进入大约1000个线程,然后达到100%CPU,停止响应,然后崩溃。这是一个16核服务器,内存为112 GB。

- 增加 因此,使用Semaphores提供的示例,这就是我所说的:

Public Class InvDir
    Private mSm as Semaphore
    Public Sub New(ByVal maxPrc As Integer)
        mSm = New Semaphore(maxPrc, maxPrc)
    End Sub

    Public Sub GetInventory(ByVal Path As String, ByRef Totals As Object, ByRef MyData As Object)
        mSm.WaitOne()

        Task.Factory.StartNew(Sub()
                Dim CurDir As New IO.DirectoryInfo(Path)
                Totals.SubDirectoryCount += CurDir.GetDirectories().Count
                Totals.FilesCount += CurDir.GetFiles().Count
                For Each CurFile As IO.FileInfo in CurDir.EnumerateFiles()
                    MyData.AddFile(CurFile.FileName, CurFile.Extension, CurFile.FullName, CurFile.Length)
                Next
                End Sub).ContinueWith(Function(x) mSm.Release())
    End Sub
End Class

1 个答案:

答案 0 :(得分:1)

您正在尝试使用磁盘I / O进行多线程处理。它可能会变得越来越慢因为你正在投入更多的线程。无论有多少线程,磁盘在物理上一次只能寻找一个位置。 (事实上​​,你提到它可以连续工作。)

如果您确实想要限制并发线程数,可以使用Semaphore。信号量就像一个syncLock,除了你可以指定允许一次执行代码的线程数。在下面的示例中,信号量允许执行三个线程。除此之外不得不等到一个完成。 MSDN页面中的一些修改代码:

Public Class Example

    ' A semaphore that simulates a limited resource pool.
    '
    Private Shared _pool As Semaphore

    <MTAThread> _
    Public Shared Sub Main()
        ' Create a semaphore that can satisfy up to three
        ' concurrent requests. Use an initial count of zero,
        ' so that the entire semaphore count is initially
        ' owned by the main program thread.
        '
        _pool = New Semaphore(0, 3)          

    End Sub

    Private Sub SomeWorkerMethod()
        'This is the method that would be called using a Task.
        _pool.WaitOne()
        Try
            'Do whatever
        Finally
            _pool.Release()
        End Try
    End Sub
End Class

每个新主题都必须调用_pool.WaitOne()。这告诉它等待轮到执行少于三个线程。每个线程都会阻塞,直到信号量允许它通过。

每个线程还必须调用_pool.Release()让信号量知道它可以允许下一个等待线程开始。这很重要,即使有例外。如果线程没有调用Release(),那么信号量将永远阻止它们。

如果它真的需要五个月,那么克隆驱动器并对同一驱动器的多个实例运行检查,每个实例都会查看不同的部分呢?