值在异步方法恢复后未更新

本文关键字:更新 恢复 异步方法 | 更新日期: 2023-09-27 18:12:40

看看这段代码:

public class SharedData
{
    public int Value { get; set; }
}
void button1_Click(object sender, EventArgs e)
{
    AAA();
}
async Task BBB(SharedData data)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    MessageBox.Show(data.Value.ToString()); //<---- I always see 0 here,
    data.Value = data.Value + 1;
}
async Task<int> AAA()
{
    SharedData data = new SharedData();
    var task1 = BBB(data);
    var task2 = BBB(data);
    var task3 = BBB(data);
    await Task.WhenAll(task1, task2, task3);
    MessageBox.Show(data.Value.ToString());  //<--- this does show 3
    return data.Value;
}

这是一个GUI (windows窗体)应用程序,这意味着只有一个线程执行每行代码。

所有BBB(data)调用调用非常快,无需等待。每个BBB调用进入BBB method,看到未完成的await并返回(AAA)。

现在,当一秒钟(大约)过去时,所有的延续都在GUI线程中发生。

Continuations不会同时发生,因为它是一个GUI线程。前面的语句

data.Value = data.Value + 1;

一定发生了

也就是说

我知道所有的BBB都是用相同的data初始值调用的,但是延续不会并发地发生

GUI线程最终必须运行:

<子>延续# 1

 MessageBox.Show(data.Value.ToString()); 
 data.Value = data.Value + 1; //So this basically should do 0-->1
....

延续#2

 MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
 data.Value = data.Value + 1;  
....

<子>延续# 3

 MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
 data.Value = data.Value + 1;

看起来延续不是作为一个整体调度的,而是作为共享量子调度的?

值在异步方法恢复后未更新

这是因为你使用MessageBox.Show调试打印和显示一个模态消息框块代码流,但不阻塞UI线程(否则你不能与消息框交互)。

因此,当通过显示消息框"阻止"第一个延续时,下一个延续可以运行,然后是第三个延续。它们都通过显示消息框被"阻止",但UI线程本身没有。

这就是为什么它们都显示0,只有当你释放消息框时,它们才能继续运行并增加变量。

您可以看到,如果在显示消息框之前使用Console.WriteLine打印该值:

async Task BBB(SharedData data)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    Console.WriteLine(data.Value);
    MessageBox.Show(data.Value.ToString());
    data.Value = data.Value + 1;
}

您会注意到,0在1秒之后被所有延续打印了3次,而不是在您取消消息框之后。

基本上,是并发运行的,但不是并行地使用同一个线程,因为它们里面有MessageBox.Show

如果您使用Console.WriteLine而不是MessageBox.Show,您将看到值一次增加一个:

async Task BBB(SharedData data)
{
    await Task.Delay(TimeSpan.FromSeconds(1));
    Console.WriteLine(data.Value);
    data.Value = data.Value + 1;
}
输出:

0
1
2