使用 Task.WhenAny 异步处理任务列表
Process a list of tasks asynchronously using Task.WhenAny
我创建了一个任务列表。一旦列表中的某个任务完成,我想处理它的结果(在本例中,打印 blob 的名称)。
代码(包含在异步函数中)如下所示:
List<Task<BlobResultSegment>> taskList = new List<Task<BlobResultSegment>>();
BlobContinuationToken token = null;
do
{
taskList.Add(blobContainer.ListBlobsSegmentedAsync(token));
}
while (token != null);
while(taskList.Any())
{
Task<BlobResultSegment> completedTask = await Task.WhenAny(taskList);
await completedTask.ContinueWith(task => {
foreach (IListBlobItem item in task.Result.Results)
{
CloudBlockBlob blob = item as CloudBlockBlob;
Console.WriteLine(blob.Name); // this statement causes the error
}
});
taskList.Remove(completedTask);
}
产生的错误:
'Object reference not set to an instance of an object.'
为什么会产生错误,我该如何解决?
ContinueWith
方法中指定的任务应该在前面的任务完成后执行,所以我不明白是什么问题。
附带说明一下,如果包含 WriteLine
方法的语句被删除,代码就会运行。
你不应该使用 ContinueWith
;这是一种危险的低级方法。
此外,我强烈建议不要使用“WhenAny
然后将其从列表中删除”的方法。这几乎是一种反模式。如果引入辅助异步方法,代码会简单得多。
关于特定于 Azure 的问题。首先,ListBlobsSegmentedAsync
的工作方式是您需要一次调用一个,用每次调用的结果更新令牌,如下所示:
List<IListBlobItem> blobs = new();
BlobContinuationToken token = null;
do
{
var result = await blobContainer.ListBlobsSegmentedAsync(token);
blobs.AddRange(result.Results);
token = result.ContinuationToken;
} while (token != null);
foreach (var item in blobs)
{
CloudBlockBlob blob = item as CloudBlockBlob;
Console.WriteLine(blob.Name);
}
至于空引用异常,很可能是因为有一个不是 CloudBlockBlob
的 blob,例如 CloudBlobDirectory
。我会推荐这样的东西:
foreach (var item in blobs)
{
if (item is CloudBlob blob)
Console.WriteLine(blob.Name);
else if (item is CloudBlobDirectory dir)
Console.WriteLine("Dir: " + dir.Prefix);
}
我创建了一个任务列表。一旦列表中的某个任务完成,我想处理它的结果(在本例中,打印 blob 的名称)。
代码(包含在异步函数中)如下所示:
List<Task<BlobResultSegment>> taskList = new List<Task<BlobResultSegment>>();
BlobContinuationToken token = null;
do
{
taskList.Add(blobContainer.ListBlobsSegmentedAsync(token));
}
while (token != null);
while(taskList.Any())
{
Task<BlobResultSegment> completedTask = await Task.WhenAny(taskList);
await completedTask.ContinueWith(task => {
foreach (IListBlobItem item in task.Result.Results)
{
CloudBlockBlob blob = item as CloudBlockBlob;
Console.WriteLine(blob.Name); // this statement causes the error
}
});
taskList.Remove(completedTask);
}
产生的错误: 'Object reference not set to an instance of an object.'
为什么会产生错误,我该如何解决?
ContinueWith
方法中指定的任务应该在前面的任务完成后执行,所以我不明白是什么问题。
附带说明一下,如果包含 WriteLine
方法的语句被删除,代码就会运行。
你不应该使用 ContinueWith
;这是一种危险的低级方法。
此外,我强烈建议不要使用“WhenAny
然后将其从列表中删除”的方法。这几乎是一种反模式。如果引入辅助异步方法,代码会简单得多。
关于特定于 Azure 的问题。首先,ListBlobsSegmentedAsync
的工作方式是您需要一次调用一个,用每次调用的结果更新令牌,如下所示:
List<IListBlobItem> blobs = new();
BlobContinuationToken token = null;
do
{
var result = await blobContainer.ListBlobsSegmentedAsync(token);
blobs.AddRange(result.Results);
token = result.ContinuationToken;
} while (token != null);
foreach (var item in blobs)
{
CloudBlockBlob blob = item as CloudBlockBlob;
Console.WriteLine(blob.Name);
}
至于空引用异常,很可能是因为有一个不是 CloudBlockBlob
的 blob,例如 CloudBlobDirectory
。我会推荐这样的东西:
foreach (var item in blobs)
{
if (item is CloudBlob blob)
Console.WriteLine(blob.Name);
else if (item is CloudBlobDirectory dir)
Console.WriteLine("Dir: " + dir.Prefix);
}