Dato il codice seguente nell'evento DoWork()
di un oggetto BackgroundWorker
, come può il concetto essere convertito nel modello Async/Await
?
Desidero eseguire più download contemporaneamente al fine di massimizzare la larghezza di banda. Dovrò anche mantenere la possibilità di incrementare una barra di avanzamento nella finestra di dialogo.
Dim oChunks As SortedDictionary(Of String, Byte())
Dim oFiles As List(Of FileInfo)
Dim iChunk As Integer
oChunks = New SortedDictionary(Of String, Byte())
oFiles = Service.Client.GetChunks(Me.Upload.UploadId, Me.Target)
oFiles.ForEach(Sub(File As FileInfo)
Worker.ReportProgress((iChunk / Me.Upload.Chunks) * 100, "Downloading...")
oChunks.Add(File.Name, Service.Client.GetChunk(File, Me.Target))
iChunk += 1
End Sub)
Una risposta in C # è benvenuta; Posso tradurre.
Modifica
In base al codice di esempio di Ewan, ho trovato la versione seguente.
Ma non funziona correttamente:
- I download continuano ad essere eseguiti in sequenza, non in parallelo
- I blocchi dell'interfaccia utente durante l'esecuzione
- L'evento
Download.Progress
non viene attivato
Cosa mi manca?
Public Class Main
Private Async Sub cmdSave_Click(Sender As Button, e As EventArgs) Handles cmdSave.Click
Dim oChunks As SortedDictionary(Of String, Byte())
Dim oFiles As List(Of FileInfo)
Dim aData As Byte()
Me.Upload = dgvUploads.CurrentRow.DataBoundItem
pnlTarget.Enabled = False
dlgSave.FileName = "{0}.zip".ToFormat(Me.Upload.UploadName)
txtFile.Text = String.Empty
If dlgSave.ShowDialog = DialogResult.OK Then
Me.SetControlsEnabled(False)
'bgwWorker.RunWorkerAsync(JobTypes.Save)
oFiles = Await Me.GetFilesAsync(Me.Upload.UploadId, Me.Target)
oChunks = Await Me.GetChunksAsync(oFiles)
aData = Await Me.MergeChunksAsync(oChunks)
File.WriteAllBytes(dlgSave.FileName, aData)
Me.SetControlsEnabled(True)
MsgBox("Download complete.", MsgBoxStyle.Information, Me.Text)
End If
End Sub
Public Async Function GetFilesAsync(UploadId As Integer, Target As Targets) As Task(Of List(Of FileInfo))
Dim oArgs As ProgressEventArgs
oArgs = New ProgressEventArgs(0, "Initializing...", ProgressBarStyle.Marquee)
Me.ReportProgress(Nothing, oArgs)
Return Await Service.Client.GetFilesAsync(UploadId, Target)
End Function
Public Async Function GetChunksAsync(Files As List(Of FileInfo)) As Task(Of SortedDictionary(Of String, Byte()))
Dim oDownload As Download
Dim oChunks As SortedDictionary(Of String, Byte())
Dim aChunks As Chunk()
Dim oTasks As List(Of Task(Of Chunk))
Dim oArgs As ProgressEventArgs
prgProgress.Value = 0
oArgs = New ProgressEventArgs(Files.Count, "Downloading...", ProgressBarStyle.Continuous)
oTasks = New List(Of Task(Of Chunk))
Files.ForEach(Sub(File)
oDownload = New Download
AddHandler oDownload.Progress, AddressOf ReportProgress
oTasks.Add(oDownload.GetChunkAsync(File, Me.Target, oArgs))
End Sub)
aChunks = Await Task.WhenAll(oTasks.ToArray)
oChunks = New SortedDictionary(Of String, Byte())
aChunks.ToList.ForEach(Sub(Chunk)
oChunks.Add(Chunk.Name, Chunk.Data)
End Sub)
Return oChunks
End Function
Public Async Function MergeChunksAsync(Chunks As SortedDictionary(Of String, Byte())) As Task(Of Byte())
Dim oChunks As List(Of Byte())
Dim iOffset As Integer
Dim oArgs As ProgressEventArgs
Dim aData As Byte()
prgProgress.Value = 0
oArgs = New ProgressEventArgs(Chunks.Count, "Saving...", ProgressBarStyle.Continuous)
aData = Await Task.Run(Function()
oChunks = Chunks.Select(Function(Pair) Pair.Value).ToList
aData = New Byte(oChunks.Sum(Function(Chunk) Chunk.Length) - 1) {}
oChunks.ForEach(Sub(Chunk)
Me.ReportProgress(Nothing, oArgs)
Buffer.BlockCopy(Chunk, 0, aData, iOffset, Chunk.Length)
iOffset += Chunk.Length
End Sub)
Return aData
End Function)
Return aData
End Function
Public Sub ReportProgress(Sender As Download, e As ProgressEventArgs)
prgProgress.Maximum = e.Maximum
prgProgress.Style = e.Style
If e.Style = ProgressBarStyle.Marquee Then
prgProgress.Value = 0
Else
prgProgress.Increment(1)
End If
lblStatus.Text = e.Status
End Sub
End Class
Public Class Download
Public Event Progress As EventHandler(Of ProgressEventArgs)
Public Async Function GetChunkAsync(File As FileInfo, Target As Targets, Args As ProgressEventArgs) As Task(Of Chunk)
Dim oChunk As Chunk
oChunk = New Chunk
oChunk.Name = File.Name
oChunk.Data = Await Service.Client.GetChunkAsync(File, Target)
RaiseEvent Progress(Me, Args)
Return oChunk
End Function
End Class
Public Class Chunk
Public Property Name As String
Public Property Data As Byte()
End Class
Public Class ProgressEventArgs
Inherits EventArgs
Public Sub New(Maximum As Integer, Status As String, Style As ProgressBarStyle)
_Maximum = Maximum
_Status = Status
_Style = Style
End Sub
Public ReadOnly Property Maximum As Integer
Public ReadOnly Property Status As String
Public ReadOnly Property Style As ProgressBarStyle
End Class