以下示例编码:
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string var1 = "sample 1";
//display in UI var1
string var1 = "sample 1.1";
//display in UI var1
}
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
string var1 = "sample 2";
//display in UI var1
string var1 = "sample 2.1";
//display in UI var1
}
private void backgroundWorker3_DoWork(object sender, DoWorkEventArgs e)
{
string var1 = "sample 3";
//display in UI var1
string var1 = "sample 3.1";
//display in UI var1
}
它是否会导致线程变慢,因为它们使用相同的变量?或者它会导致在UI上显示错误的值,因为值总是在变化?我的程序会有很多线程,所以我担心潜在的不可预见的后果。
答案 0 :(得分:1)
这些是local variables,它们彼此独立存在,编译器和运行时永远不会混淆它们,因为它们是...... local 到声明它们的位置。实际上,局部变量不是线程的关注点,请参阅Thread safety and local variables [*]。
编译后,局部变量的名称将丢失(它们将相当于 - local variable 1
,local variable 2
等等。)。也就是说,在Microsoft Intermediate Language中,局部变量的名称是无关紧要的。请参阅OpCodes.Ldloc Field。
它是否会导致线程变慢,因为它们使用相同的变量?
没有。这些都是毫无根据的担忧。这些局部变量彼此无关。
或者它会导致在UI上显示错误的值,因为值总是在变化吗?
无论变量名称如何,都可能发生这种情况。重要的是您在UI中显示的价值,以及您何时何地展示它。持有它的变量名称没有影响。
我的程序会有很多线程,所以我担心潜在的不可预见的后果。
不要担心局部变量。一旦我们开始讨论跨线程的某种形式的共享内存,那么你就有理由担心。不,不会在线程之间共享局部变量,让我在这里说清楚:它们是本地的 [**]。
我想建议Joseph Albahari的系列Threading in C#。尽管已经过时了[***]但写得很好,有明确的例子,并且可以获得所有基础知识。
话虽如此,命名变量对于代码的可读性和可维护性非常重要。无论如何,我没有心情去讲道。所以,你做到了。我只会在这个问题上说:下次你看到一个变量并且你不确定它是什么或者你可能在哪里使用它时,请考虑一下。
[*]:answer to the linked question提到了两种可以暴露局部变量的方法。两者都相当于将局部变量升级到幕后的一个非对象对象的字段(yield return
将值复制到隐藏的IEnumerator
,另一方面如果在本地创建closure变量并共享它,你在一个隐藏的匿名类中共享局部变量。
[**]:即使你使用async/await
并且该方法在另一个线程中恢复,两个线程也不可能共享本地变量(它易手,但你通常没有理由担心这一点,除非你使用ThreadLocal
或类似的。)
[***]:这些天我们将使用async/await
,事实上,你为什么要使用BackgroundWorker
?