2015-09-14 91 views
7

后不更新寻找在这个代码:值异步方法恢复

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(窗口形式)应用程序,这意味着只有一个执行的代码的每一行线程。

全部BBB(data)调用非常快速地调用,无需等待。 每个BBB调用进入BBB method,看到await不完成并返回(到AAA)。

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

问题

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

data.Value = data.Value + 1; 

必须发生。

换句话说,

我知道,所有BBB s的与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; 

它看起来像延续预计不会作为一个整体,但作为共享量子?

+0

@Eser我不明白,每次延续了自己的gui线程。这里有**没有**其他线程。为什么锁定?这不是(!)在线程池线程中运行,这意味着没有上下文可以保留(并且每个延续可以在另一个线程池线程中运行)。 –

+0

更改'BBB'以接受并使用延迟值:'异步任务BBB SharedData data,int delay)',然后传递不同的值而不是相同的'1'。想知道为什么现在你一次看到三个消息框,而不是一次一个? :) – Noseratio

+0

@Noseratio是的,我不知道:-)你能解释一下吗? [此代码](http://i.imgur.com/pWUXCXW.png)一起显示3 MSgBox,而不是1(如我的示例中)。你能解释为什么吗? –

回答

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; 
} 

你会发现,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 
+0

第二段不清楚(对我来说)。 :_当第一次继续通过显示一个消息框被“阻止”时,下一次继续可以运行,然后第三次?你可以请示步骤吗? –

+0

@RoyiNamir显示一个模式消息框阻止当前的代码流,但它不会通过阻塞线程(否则应用程序将冻结)来实现。这意味着第一个延续卡住了,但下一个可以在UI线程上运行。 – i3arnon

+0

因此,当我看到第一个消息框时,那时已经有2个继续,它们已经调用了'MessageBox.Show(data.Value.ToString());',其中未提高值? –