刚进入异步编程,我的最终目标是异步获取给定文件集的sha1哈希值,然后继续使用计算出的哈希值处理所述文件。我发现以下MSDN博客文章谈到如何在任务完成时处理任务结果:链接
整篇文章都是用C#编写的,而我的项目是在VB.NET中的。我曾尝试自己将C#代码重写为VB,但是我必须缺少关键的步骤,否则我将无法完全理解Async
/Await
编程的过程/语法。
我在以下几行中收到以下错误:
错误1“等待”仅当包含在用“异步”修饰符标记的方法或lambda表达式中时才能使用。
Dim t As Task(Of Integer) = Await bucket
Dim result As Integer= Await t
Dim t As Task(Of String) = Await bucket
Dim result As String = Await t
通过添加Async
到包含的Sub声明中,我可以使错误消失。但是,如果这样做,我会收到另一个错误,因为containing方法是main()
并且它是控制台应用程序。
错误1无法将“主要”方法标记为“异步”。
所以我想我的问题是,如何Await
在不使包含方法异步的情况下使用异步任务?我下面的代码只是一个WinForms项目中实现的测试器,我宁愿远离非本机.NET片段。
以下是我从C#转换的完整代码,以及用于计算文件的sha1哈希值的少量代码:
Option Strict On
Option Explicit On
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Module Module1
Async Sub main()
' From the MSDN article
Dim taskArr As Task(Of Integer)() = {Task(Of Integer).Delay(3000).ContinueWith(Function(x) 3I), _
Task(Of Integer).Delay(1000).ContinueWith(Function(x) 1I), _
Task(Of Integer).Delay(2000).ContinueWith(Function(x) 2I), _
Task(Of Integer).Delay(5000).ContinueWith(Function(x) 5I), _
Task(Of Integer).Delay(4000).ContinueWith(Function(x) 4I)}
For Each bucket As Task(Of Task(Of Integer)) In Interleaved(taskArr)
Dim t As Task(Of Integer) = Await bucket ' Error Here
Dim result As Integer = Await t ' Error Here
Console.WriteLine("{0}: {1}", DateTime.Now, result)
Next
'My bit of code for computing the file hashes
Dim tasks As New List(Of Task(Of String))
Array.ForEach(New DirectoryInfo("C:\StackOverflow").GetFiles("*", SearchOption.AllDirectories), Sub(x) tasks.Add(getHashAsync(x)))
For Each bucket As Task(Of Task(Of String)) In Interleaved(tasks)
Dim t As Task(Of String) = Await bucket ' Error Here
Dim result As String = Await t ' Error Here
Console.WriteLine(result)
Next
End Sub
' Original C# code that I converted to VB myself
Public Function Interleaved(Of T)(tasks As IEnumerable(Of Task(Of T))) As Task(Of Task(Of T))()
Dim inputTasks As List(Of Task(Of T)) = tasks.ToList()
Dim buckets() As TaskCompletionSource(Of Task(Of T)) = New TaskCompletionSource(Of Task(Of T))(inputTasks.Count - 1I) {}
Dim results() As Task(Of Task(Of T)) = New Task(Of Task(Of T))(buckets.Length - 1I) {}
For i As Integer = 0I To buckets.Count - 1I Step 1I
buckets(i) = New TaskCompletionSource(Of Task(Of T))()
results(i) = buckets(i).Task
Next
Dim continuation As New Action(Of Task(Of T))(Function(completed As Task(Of T))
Dim bucket As TaskCompletionSource(Of Task(Of T)) = buckets(Interlocked.Increment(-1I))
Return bucket.TrySetResult(completed)
End Function)
For Each inputTask As Task(Of T) In inputTasks
inputTask.ContinueWith(continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default)
Next
Return results
End Function
' Get the sha1 hash of the file
Private Async Function getHashAsync(fle As FileInfo) As Task(Of String)
Using strm As New IO.FileStream(fle.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)
Return Await New Task(Of String)(Function() As String
Dim sb As New Text.StringBuilder()
Using sha1 As New System.Security.Cryptography.SHA1CryptoServiceProvider()
Array.ForEach(sha1.ComputeHash(strm), Sub(x As Byte) sb.Append(x.ToString("x2")))
End Using
Return sb.Append(" | ").Append(fle.FullName).ToString
End Function)
End Using
End Function
End Module
await
仅是等待Task
的结果的一种选择,其次是Task
静态方法的用法,用于按时等待所有任务的结果。
据我所知,你正在创建的列表Tasks
中Tasks
的T
,是这样的:
var list = new List<Task<Task<string>>>();
如果是这样,您可以做的最简单的事情就是将任务列表放平,然后用Task.WaitAll()
调用两次的方法等待其中的所有任务,如下所示:
var list = new List<Task<Task<string>>>();
Task.WaitAll(list.ToArray());
// now we aggregate the results
var gatheredTasks = list.Select(t => t.Result);
Task.WaitAll(gatheredTasks.ToArray());
foreach (var task in gatheredTasks)
{
Console.WriteLine(task.Result);
}
在这种情况下,您将获得来自的所有奖励TPL
,因为有很多技术可以用来平衡工作,等等,并且您将获得所需的所有结果。
如果要按出现的顺序获得结果,可以编写带Task.WaitAny()
方法的循环,但是我认为这不是一个好选择。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句