【问题标题】:Handling multi-threading using TPL in windows service (conception)在 Windows 服务中使用 TPL 处理多线程(概念)
【发布时间】:2012-08-13 18:39:34
【问题描述】:

我有一个 vb.net 服务,它需要一些线程来分别处理每个函数调用并避免时间消耗。

我有 2 个函数需要实现线程:

在问我的问题之前,这是我的两个功能:

1- LaunchTasks() :如果任务启动良好,则计算此任务的“NextRunDate”,否则跳过它。

'Dim oThread As Threading.Thread
For Each oRow As DataRow In oDatatable.Rows
    Dim oCLASSE_Task As New CLASSE_Task
    If oCLASSE_Task.Load(oRow.Item("Mytask")) Then

        'oThread = New Threading.Thread(AddressOf oTask.launchSteps)
        'oThread.Priority = Threading.ThreadPriority.Normal
        'oThread.Start()

        Dim oThread = System.Threading.Tasks.Task(Of Boolean).Factory.StartNew(Function() oCLASSE_Task.launchSteps())

    End If
Next
' Need to wait until all threads finish

2- 计算运行日期()

'It's called for each object in CLASSE_Task

'Dim oThread As Threading.Thread
For Each oRow As DataRow In oDatatable.Rows
    Dim oCLASSE_Task As New CLASSE_Task
    If oCLASSE_Task.Load(oRow.Item("Mytask")) Then

        Dim oThreadTask = System.Threading.Tasks.Task(Of Boolean).Factory.StartNew(Function() oCLASSE_Task.calculateNextRunDate())

        'oThread = New Threading.Thread(AddressOf oTask.calculateNextRunDate)
        'oThread.Priority = Threading.ThreadPriority.Normal
        'oThread.Start()

    End If
Next
' Need to wait until all threads finish

我总是先调用 LaunchTask(),然后再调用 calculateRunDates()(如果我在数据库中获得新记录)。

在启动 calculateRunDates() 之前,我必须等待函数 LaunchTask() 中的所有线程完成。

  • 如何使用 TPL(我以前从未使用过),比如 thread.join() 来做到这一点?

  • 在这种情况下我应该使用线程还是 TPL?

  • 如何在服务中使用 TPL 处理异常(类似于 that)?

注意:我的 CLASSE_Task 使用 SyncLock 锁定。

没有足够的例子使用 vb.net,主要是 C#。

希望我已经足够清楚了。

【问题讨论】:

    标签: .net vb.net multithreading task-parallel-library


    【解决方案1】:

    首先,回答您的问题:

    如何使用 TPL(我以前从未使用过),比如 thread.join() 来做到这一点?

    您应该为此使用task.Wait()。如果你想等待几个Tasks,你可以使用Task.WaitAll()

    在这种情况下我应该使用线程还是 TPL?

    您应该使用 TPL。它更易于使用且更高效。

    如何在服务中使用 TPL 处理异常?

    如果Task 中的代码引发异常,然后您在该TaskWait()(或在多个Tasks 上WaitAll()),它将引发包含引发异常的AggregateException。如果你不打电话给Wait(),你可以使用ContinueWith(),正如你链接到的问题所暗示的那样。


    但是对于您的代码,我认为更好的选择是使用Parallel.ForEach():它会为您创建Tasks,它会更有效地完成它(它在迭代之间共享Tasks ) 并且您不必处理等待,因为当它返回时,所有迭代都已完成:

    Parallel.ForEach(oDatatable.Rows.Cast(Of DataRow)(),
                     Sub(oRow)
                         Dim oCLASSE_Task As New CLASSE_Task
                         If oCLASSE_Task.Load(oRow.Item("Mytask")) Then
                             oCLASSE_Task.launchSteps()
                         End If
                     End Sub)
    

    【讨论】:

    • 谢谢,我将尝试使用以下代码运行和测试我的程序!
    • 有时,它会跳过一些记录。某些记录未更新或未记录。你有什么主意吗 ?我什至无法调试。有办法调试吗?
    • 应该可以正常调试了。断点应该可以正常工作。
    • 事实上,当我使用断点时,它会中断并正确保存记录。但是当我不放置断点时,它只是跳过了launchSteps()或calculateNextRunDate()中的一些函数,并且记录不会保存在数据库中。我必须添加一些东西来处理数据库记录?
    【解决方案2】:

    要等待多个任务完成,您可以使用 Task.WaitAll(...) 方法。有关示例,请参阅this。 本文还展示了如何处理任务引发的异常。将 try/catch 放在 Task.WaitAll() 周围并检查捕获的 AggregateException 以获取任务抛出的单个异常。

    但是,您的代码似乎会受益于使用 Parallel.ForEach API,这将提供更智能的循环分区。简单地为每一行创建一个单独的任务可能会使线程池过载。

    【讨论】:

    • Parallel.ForEach 将为您做什么,它将尝试创建最佳数量的并发任务以在循环上工作。这个数字将接近您机器上的 CPU 内核数。这比只为每个 DataRow 创建一个任务要好,因为它减少了上下文切换,并且不会创建比在您的机器上可能同时运行的线程多得多的线程。
    • 好的,我明白了。我将使用 Parallel.ForEach(),这似乎更适合我的情况。
    • @Volma 使用多个Tasks 很可能不会创建很多线程,因此不会导致上下文切换。但你是对的,它比使用Parallel.ForEach() 效率低。
    • @svick 为什么不呢?线程的数量和它们的创建速率将由线程池控制,但它很可能比 Parallel.ForEach() 大得多
    • @Volma 不是真的。使用Parallel.ForEach(),使用的线程数也由ThreadPool 控制(除非您明确设置最大值),因此适用相同的规则。
    猜你喜欢
    • 2014-03-04
    • 2019-07-19
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 2018-12-18
    • 2013-04-07
    • 2012-07-16
    • 1970-01-01
    相关资源
    最近更新 更多