VB.net ContinueWith

问题描述:

我有这个代码,它循环遍历我的列表中的所有帐户,然后对每个帐户使用任务的帐户做一些事情,以加速此过程。每次程序完成此操作时,我都希望用户界面更新进度栏。我以前使用Invoke,但它不是最好的选择,我无法得到它的工作。现在我知道这可以使用后台工作来完成,但这不是让应用程序多线程的最佳方式,所以我使用了这种方法。而不是援引我听说ContinueWith,但我似乎无法得到它的工作,我没有得到任何错误消息只是一个红色的下划线。 代码:VB.net ContinueWith

progressBar.Value = 0 
    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
            While checked = False 
             If proxies.Count = 0 Then 
              Exit Sub 
              'Also can't think of a good way to stop searching through accounts when there are no proxies left in my queue. 
             End If 
             Dim proxy As New WebProxy(proxies(0)) 
             proxies.TryDequeue(0) 
             'Do something 
            End While 
            checkedAmount += 1 
            Dim progress As Integer = ((checkedAmount/combos.Count) * 100) 
            Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext()) 'Error here 
           End Sub) 
     tasks.Add(t) 
    Next 
    Task.WaitAll(tasks.ToArray()) 

我没有得到任何错误代码如下所示: enter image description here

我也试图把一个子之类的东西,但铅不了了之了。 感谢您提前提供任何帮助。与调用

更新的尝试:

Private Delegate Sub UpdateProgressBarDelegate(ByVal progressBarUpdate As ProgressBar, ByVal value As Integer) 

Dim checkedAmount As Integer = 0 
Dim checked As Boolean = False 
Private Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click 
    progressBar.Value = 0 
    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
            While checked = False 
             proxies.TryDequeue(0) 
             'do stuff 
            End While 
            checkedAmount += 1 
            Dim progress As Integer = ((checkedAmount/combos.Count) * 100) 
            If Me.InvokeRequired = True Then 
             Me.Invoke(New UpdateProgressBarDelegate(AddressOf UpdateProgressBar), progressBar, progress) 
            Else 
             UpdateProgressBar(progressBar, progress) 
            End If 
            'Task.ContinueWith(progressBar.Value = progress, TaskScheduler.FromCurrentSynchronizationContext()) 
           End Sub) 
     tasks.Add(t) 
    Next 
    Task.WaitAll(tasks.ToArray()) 
End Sub 

Private Sub UpdateProgressBar(ByVal ProgressBarUpdate As ProgressBar, progress As Integer) 
    progressBar.Value = progress 
End Sub 

还不行不知道为什么?

+1

'我以前使用Invoke,但它不是最好的选择' - 呃,是的。这是少数几种方法之一(或者甚至是唯一的方法),你可以实际调用UI线程。 - 另外,FYI,'Task.ContinueWith()'也需要你调用,因为它也运行后台任务/线程。 –

+0

虽然调用不必那么复杂!你可以编写一个扩展方法来为你做所有事情,这样你只需要**一行**就可以调用。请参阅我的回答以获取有关调用的更多信息,以及如何简化它(从_ **访问UI线程** _开始):https://stackoverflow.com/a/45571728/3740093 –

+0

好的,我有这个现在的代码,但它甚至不能正常工作?它不会更新,也不会在后台运行。 – 1ben99

现在我知道这可以通过使用一个后台工作要做,但是这是不是让你的应用程序的多线程

排序的最佳方式。

BackgroundWorker是单独运行许多不同任务的糟糕方法。没有人想为每个任务处理单独的BackgroundWorker组件。但一个 BackgroundWorker是一个伟大的方式来产生一个额外的线程来管理所有其他任务和更新进度栏。这是一个简单的解决方案。

无论哪种方式,您要做的一件事当然就是移动代码以将ProgressBar更新为单个任务。把它放在任务内部会违反关注点分离。一旦你这样做了,你还需要将呼叫更改为WaitAll(),以便在知道你有多少任务的循环中使用WaitAny(),因此当每个任务完成时仍然可以更新ProgressBar。这样可能会有修复当前问题的副作用。

Private Async Sub startBtn_Click(sender As Object, e As EventArgs) Handles startBtn.Click 

    Dim tasks As New List(Of Task)() 
    For Each account In combos 
     Dim t As Task = Task.Run(Sub() 
           While Not checked 
            proxies.TryDequeue(0) 
            'do stuff 
           End While 
           End Sub) 
     tasks.Add(t) 
    Next 


    progressBar.Value = 0 
    For i As Integer = 1 To tasks.Count 
     Dim t = Await Task.WhenAny(tasks) 
     tasks.Remove(t) 
     progressBar.Value = (i/combos.Count) * 100 
    Next i 
End Sub 

1这里的问题说明了我们关心的关注点分离,在所有的原因之一。一旦我解决了这个问题,代码变得更简单了,令人沮丧的错误消失了。

+0

我很欣赏你的意见,但我更愿意至少调用它,因为我尝试使用后台工作,而且速度较慢,并且使得我的UI在执行任务时真的很慢并且很麻烦。 – 1ben99

+0

+1用于编辑。我忘记了Task.WaitAll()调用冻结了UI线程(也就是说,除非用'Await'调用)。 –

+1

@VisualVincent哦,他可能还在那样做。这个窗台在UI线程上调用某种WaitX()。这就是为什么他应该将其转移到BackgroundWorker。但至少这促使事情朝着正确的方向发展。 –