异步方法恢复后,值不会更新

Roy*_*mir 7 .net c# winforms async-await

看看这段代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

BBB(data)无需等待即可快速调用所有调用.每次BBB调用进入BBB method,看await哪些没有完成并返回(返回AAA).

现在,当经过一秒(大约)时,所有延续都发生在GUI线程中.

延续不会同时发生,因为它是一个GUI线程.所以先前的声明:

data.Value = data.Value + 1;
Run Code Online (Sandbox Code Playgroud)

一定发生了.

换一种说法 ,

我知道所有BBBs都是以相同的初始值调用的data,但是并发不会同时发生

GUI线程最终必须运行:

继续#1

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

继续#2

 MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
 data.Value = data.Value + 1;  
....
Run Code Online (Sandbox Code Playgroud)

继续#3

 MessageBox.Show(data.Value.ToString()); // Why data.Value still "0" ??
 data.Value = data.Value + 1;
Run Code Online (Sandbox Code Playgroud)

看起来这些延续不是作为一个整体而是作为共享量子安排的?

i3a*_*non 5

这是因为您正在使用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;
}
Run Code Online (Sandbox Code Playgroud)

您会注意到,0在1秒之后所有延续时间打印3次,而不是在您关闭消息框之后.

基本上,continuation同时运行,但不是并行使用相同的线程,因为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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

0
1
2
Run Code Online (Sandbox Code Playgroud)