【问题标题】:Can I guarantee runnable task continuations have been run?我可以保证已经运行了可运行的任务延续吗?
【发布时间】:2019-04-07 03:29:53
【问题描述】:

这是我正在处理的一段代码中显着减少的测试用例:

var i = 0;

var taskCompletionSource = new TaskCompletionSource<object>();
var task = taskCompletionSource.Task;

Task.Run(async () => 
{
    await task;
    i = 1;
});

// Synchronously complete `task`
taskCompletionSource.SetResult(null);

// ???

Console.WriteLine(i);

假设此代码在async 方法的上下文中运行,应该替换// ??? 以确保此代码打印1 而不是0

我相信我理解为什么在编写程序时总是会打印0——代码是同步执行的,调度程序没有任何结果。但我很惊讶地得知这一点

await Task.Yield();

还不够。有点讽刺的是(但完全可以理解,因为它不涉及异步执行)

await task;

另一方面,

await Task.Delay(1);

似乎已经足够了,但我不清楚这是保证还是时间上的意外。

以另一种方式问这个问题:我可以编写任何(合理的)代码来保证task 的所有延续都在继续之前运行吗?

【问题讨论】:

  • 编写的代码不起作用,因为您没有等待从 Task.Run(...) 创建的任务。你完成了task,但Console.WriteLine(i)i = 1之前被执行。但我不确定你要做什么。见fiddler
  • await Task.Delay(1); 起作用的原因可能是因为它强制线程移位,因此任务将在Console.Writeline 之前执行。
  • 顺便说一句。这是一个糟糕的使用模式。如果内部方法的主体返回一些数据,则应使用return i; 代替。在这种情况下,初始化将在内部主体中完成。这个概念称为 ENCAPULATION,是 OOP 的四大支柱之一。
  • 关闭i 只是为了说明问题的一个例子,但谢谢。

标签: c# async-await task task-parallel-library taskcompletionsource


【解决方案1】:

假设这段代码在异步方法的上下文中运行

var i = 0;

await Task.Run(async () => 
{
    await task;
    i = 1;
});

Console.WriteLine(i);

var i = 0;

await task;
i = 1;

Console.WriteLine(i);

【讨论】:

  • 这不回答问题 (Assuming that this code runs in the context of an async method, what should replace // ??? to ensure that this code prints 1 rather than 0?)
  • 本质上没有错,但这是对他的代码的重写,这可能是不可能的,因为他想在Task.RunSetResult之间做点什么。
  • 问题写在哪里?
  • significantly reduced test casewhat should replace // ??? to ensure that this code prints 1 rather than 0?(后者为粗体)。
【解决方案2】:

我能否保证已运行可运行的任务延续?

await他们。

var i = 0;

var taskCompletionSource = new TaskCompletionSource<object>();
var task = taskCompletionSource.Task;

var continuation = Task.Run(async () => 
{
    await task;
    i = 1;
});

// Synchronously complete `task`
taskCompletionSource.SetResult(null);

// wait for the continuation
await continuation;

// ouputs 1
Console.WriteLine(i);

如果您使用的是异步方法,这将有效。如果不是,请使其异步。您也可以在技术上阻止(.Wait() 而不是 await),但这会导致死锁,所以要小心。

【讨论】:

    猜你喜欢
    • 2017-06-11
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-23
    • 1970-01-01
    相关资源
    最近更新 更多