首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ITargetBlock<TInput>.Completion.ContinueWith()的最佳实践

ITargetBlock<TInput>.Completion.ContinueWith()的最佳实践
EN

Stack Overflow用户
提问于 2014-12-09 14:40:33
回答 1查看 1.4K关注 0票数 6

这个问题涉及使用ContinueWith()处理TPL数据库完成时的最佳实践。

ITargetBlock.Completion()方法允许您使用ContinueWith()异步处理数据库的完成。

考虑下面的控制台应用程序代码,它演示了一个非常基本的用法:

代码语言:javascript
复制
private static void Main()
{
    test().Wait();
}

static async Task test()
{
    var transform = new TransformBlock<int, double>(i => i/2.0);
    var output    = new ActionBlock<double>(d => Console.WriteLine(d));

    // Warning CS4014 here:
    transform.Completion.ContinueWith(continuation => output.Complete());
    transform.LinkTo(output);

    for (int i = 0; i < 10; ++i)
        await transform.SendAsync(i);

    transform.Complete();
    await output.Completion;
}

该代码有一个非常简单的TransformBlock,它将整数除以2.0,并将它们转化为双倍。转换后的数据由ActionBlock处理,它只将值输出到控制台窗口。

产出如下:

代码语言:javascript
复制
0
0.5
1
1.5
2
2.5
3
3.5
4
4.5

TransformBlock完成时,我也要完成ActionBlock。这样做很方便:

代码语言:javascript
复制
transform.Completion.ContinueWith(continuation => output.Complete());

问题就在这里。因为这是在一个async方法中,而且我忽略了来自ContinueWith()的返回值,所以我得到了一个编译器警告:

警告CS4014:由于没有等待此调用,因此在调用完成之前,将继续执行当前方法。考虑将“等待”运算符应用于调用的结果.

显然,我不能按照警告的建议进行await调用--如果这样做,代码会挂起,因为在调用transform.Complete()之前,CompleteWith()任务无法完成。

现在,我在处理警告本身方面没有问题(我只需要将任务取消,或者将任务赋值给变量,或者使用.Forget()任务扩展等等)--但下面是我的问题:

  • 以这种方式处理链接DataBlock完成是否安全?
  • 有更好的办法吗?
  • 有什么重要的事我忽略了吗?

我认为,如果我在延续中做的不是output.Complete(),我就必须提供异常处理--但也许仅仅调用output.Complete()也充满了危险?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-12-09 15:31:04

虽然您可以自己实现完成传播,但是TPL使用DataflowLinkOptions.PropagateCompletion为您做了它。

代码语言:javascript
复制
transform.LinkTo(output, new DataflowLinkOptions {PropagateCompletion = true});

如果您仍然希望自己实现该任务,则可以解决这个问题,即存储任务,并在适当时使用Task.WhenAll等待它。

代码语言:javascript
复制
static async Task test()
{
    var transform = new TransformBlock<int, double>(i => i/2.0);
    var output    = new ActionBlock<double>(d => Console.WriteLine(d));

    // Warning CS4014 here:
    var continuation = transform.Completion.ContinueWith(_ => output.Complete());
    transform.LinkTo(output);

    for (int i = 0; i < 10; ++i)
        await transform.SendAsync(i);

    transform.Complete();
    await Task.WhenAll(continuation, output.Completion)
}

这使您能够处理output.Complete中的任何异常并删除警告。

票数 8
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27381582

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档