🌴前言
最近一个项目中需要用到多线程, 而在研究多线程的过程中发现了 foreach 的一个特性.
❓问题
网上有一种说法, 如下代码会出现一个问题, 导致最后输出的结果为: 五个 555 字符串
.
理由和之前说过的 "闭包和委托" 结合容易引起的问题一样, 下面是一个博主的解释:
由于被置于 ThreadPool 中的操作时异步的, 还没有来的及执行的时候, inFor 变量已经被循环改变, 等到 ThreadPool 执行的时候, inFor 已经是最后一个值了, 也就是 555, 所以最终的结果是输出了五次 555.
1 2 3 4 5 6 7 8 9 10 11 12
| public static void MultiTest() { var list = new List<int> {111, 222, 333, 444, 555}; foreach (var inFor in list) { System.Threading.ThreadPool.QueueUserWorkItem(state => { DebugUtil.Log($"<color='red'>{inFor}</color>"); }); } }
|
✨结论
而实际经过实验之后发现, 目前 C# 和 Unity 中都不会再出现这种问题, 下面是我实验的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public static void MultiTest() { var list = new List<int> {111, 222, 333, 444, 555}; foreach (var inFor in list) { System.Threading.ThreadPool.QueueUserWorkItem(state => { DebugUtil.Log($"<color='red'>{inFor}</color>"); }); } Thread.Sleep(10); int outFor; foreach (var inFor in list) { outFor = inFor; System.Threading.ThreadPool.QueueUserWorkItem(state => { DebugUtil.Log($"<color='yellow'>{outFor}</color>"); }); } }
|
最终得到的结果是:
可以看到, 当仅使用 foreach 时得到的结果是完全正确的, 只有当使用一个外部变量的时候才会出现闭包机制引发的 Bug, 因此可得出表现上的结论:
foreach 中的临时变量从表现上来看可以认作每次循环后都是一个新的变量.