Task.WhenAll() 在等待任务上与ContinueWith() 一起使用时任务被取消

问题描述 投票:0回答:1

当创建需要执行的任务列表时,其中一些任务可能会失败,但不应停止代码的执行,我想出了仅在出错的任务上使用 continuewith ,但是当在任务集合上调用 Task.WhenAll() 时它抛出任务被取消的异常:

使用的代码片段:

 var deletOldFiles = dbDraft
                    ?.Documents?.Select(s => s.Id)
                    .Select(id =>
                        _fileStorage
                            .DeleteFileAsync(
                                _fileStorageConfiguration.DefaultFileCollectionName,
                                id,
                                cancellationToken
                            )
                            .ContinueWith(
                                t =>
                                {
                                    _logger.LogError(
                                        "Could not delete document with identifier: {id}",
                                        id
                                    );
                                },
                                TaskContinuationOptions.OnlyOnFaulted
                            )
                    );

                if (deletOldFiles is not null)
                    await Task.WhenAll(deletOldFiles);

即使调用Task.WhenAll时,主任务DeleteFileAsync()执行成功,但Task.WhenAll抛出异常。

当我删除ContinueWith()调用时,代码工作正常并且Task.WhenAll()完成。但我希望如果某些文件删除失败,继续删除其他文件。

.net
1个回答
0
投票

ContinueWith()
当任务的执行条件不满足时,即在您的情况下,当前面的任务完成而没有错误时,任务将被取消。 并且由于您返回
ContinueWith()
任务,因此
Task.WhenAll
方法对所有延续进行操作,而不是对原始任务进行操作。 快速修复 - 返回原始任务,忽略取消:

var deletOldFiles = dbDraft
    ?.Documents?.Select(s => s.Id)
    .Select(id =>
        {
            var t = _fileStorage
                .DeleteFileAsync(
                    _fileStorageConfiguration.DefaultFileCollectionName,
                    id,
                    cancellationToken
                );
            t.ContinueWith(
                t =>
                {
                    _logger.LogError(
                        "Could not delete document with identifier: {id}",
                        id
                    );
                }, TaskContinuationOptions.OnlyOnFaulted);
            return t;
        }
    );

if (deletOldFiles is not null)
    await Task.WhenAll(deletOldFiles);

有几个时刻需要提及:

  • 您需要
    Enumerable.Select
    打电话两次吗?一次就够了。
  • 为什么需要
    dbDraft
    的零传播?可以为空吗, 认真的吗?
© www.soinside.com 2019 - 2024. All rights reserved.