【问题标题】:Consuming an synchronous or asynchronous method as a Task将同步或异步方法作为任务使用
【发布时间】:2012-11-04 03:19:47
【问题描述】:

我正在查看 codeplex 上的下载管理器类型项目并遇到了这个: http://nthdownload.codeplex.com/

浏览我在AddDownloads 等方法中运行的代码,如下所列:

AddDownloads 启动 _downloadQueue.AddDownloads 任务并继续执行 viewMaintenanceTask 任务。如果您查看这 2 个任务和下游发生的方法和事情,似乎一切都是同步的。

同时阅读这篇博文,Synchronous tasks with Task 我试图了解将同步方法包装在TaskCompletionSource 中的优势(如果有的话)。是因为它为 API 使用者提供了在单独的线程上启动任务的选项,还是仅仅因为您想将该方法用作 Task。包裹在TaskCompletionSource 中的同步方法是否受益于并行处理?

private Task<QueueOperation> AddDownloads(IEnumerable<IDownload> downloads, out Task<QueueOperation> startTask)
{
    var addTask = _downloadQueue.AddDownloads(downloads, out startTask);

    // Maintain views
    var viewMaintenanceTask = addTask.ContinueWith(t =>
    {
        if (t.Exception == null)
        {
            var addedDownloads = t.Result.DownloadErrors.Where(k => k.Value == null).Select(k => k.Key).ToList();
            var activeDownloads = ActiveDownloads.ToList();
            AddToActiveDownloads(addedDownloads.Except(activeDownloads).ToList(), false);
        }
        else
        {
            // Rethrow exception, this ensures it'll bubble up to any further ContinueWith chained off this task
            throw t.Exception;
        }
        return t.Result;
    });

    return viewMaintenanceTask;
}

博客文章中的示例方法,将同步操作包装在 TaskCompletionSource 中:

var tcs = new TaskCompletionSource<object>();

try
{
    object result = model.Deserialize(stream, null, type);
    tcs.SetResult(result);
}
catch (Exception ex)
{
    tcs.SetException(ex);
}

return tcs.Task;

【问题讨论】:

    标签: c# async-await


    【解决方案1】:

    包装在 TaskCompletionSource 中的同步方法是否受益于并行处理?

    没有。创建TaskCompletionSource 不会以任何方式、形状或形式创建新线程。

    您在底部给出的代码毫无意义——当方法返回时,任务已经完成(或出错)。 只有如果你必须使用一个任务,它会有任何用处。我可能会将其更改为:

    try
    {
        return Task.FromResult(model.Deserialize(stream, null, type));
    }
    catch (Exception ex)
    {
        // There's no Task.FromException, unfortunately.
        var tcs = new TaskCompletionSource<object>();
        tcs.SetException(ex);
        return tcs.Task;
    }
    

    在 C# 中,这相当于编写没有 await 表达式的 async 方法:

    public static async Task<object> Deserialize(Model model, Stream stream,
                                                 Type type)
    {
        return model.Deserialize(stream, null, type);
    }
    

    如果您想要真正的并行性,您应该使用 Task.Run (.NET 4.5) 或 Task.Factory.StartNew (.NET 4)。

    【讨论】:

    • 因此,在这两个示例中,没有任何理由在 TCS 中包装代码。
    • 等待包含在 TCS 中的同步代码与调用它的方式与通常调用方法相同吗?
    • @DerekBeattie:如果 TCS 已经完成,它们基本上是等价的。有一些细微的差别,但我怀疑它们是否适用于此。
    猜你喜欢
    • 1970-01-01
    • 2015-03-08
    • 2019-11-25
    • 2020-09-15
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多