线程,列表和循环不是一个好主意?(Thread, List and looping not a good idea?)

编程入门 行业动态 更新时间:2024-10-22 19:29:54
线程,列表和循环不是一个好主意?(Thread, List and looping not a good idea?)

为了提高WrapPanel的性能,我已经为我的WP7应用程序引入了线程。 在一个List中有一个很长的Item -object列表,逐个添加到另一个列表中。 我有以下两个清单:

public List<Item> OriginalItems; public List<Item> CopyOfItems;

放在BackgroundWorker.DoWork事件处理程序中的逻辑如下:

workerThread.DoWork += new DoWorkEventHandler((object sender, DoWorkEventArgs e) => { foreach (var item in OriginalItems) { Deployment.Current.Dispatcher.BeginInvoke(() => { CopyOfItems.Add(item); }); // I feel sooo sleepy } });

现在,当我用Thread.Sleep(150)替换我的注释时,这很好用 - 但是任何更少(并且偶尔使用更大的值)会使代码连续多次放入相同的元素中。

这是为什么,以及如何解决?

In order to up performance on a WrapPanel, I have introduced threading to my WP7 app. There's a long List of Item-objects in one list, that one by one is added to another `List. I have the following two lists:

public List<Item> OriginalItems; public List<Item> CopyOfItems;

The logic that's put inside the BackgroundWorker.DoWork event handler is as follows:

workerThread.DoWork += new DoWorkEventHandler((object sender, DoWorkEventArgs e) => { foreach (var item in OriginalItems) { Deployment.Current.Dispatcher.BeginInvoke(() => { CopyOfItems.Add(item); }); // I feel sooo sleepy } });

Now, this works just fine when I replace my comment with Thread.Sleep(150) - but anything less (and every once in a while even with larger values) makes the code put in the same element several times in a row.

Why is this, and how can it be fixed?

最满意答案

这是C#中已知的皱纹 - 实际上是在C#5中修复的皱纹。当您从lambda表达式中的foreach循环捕获循环变量时,您将捕获一个变量 。 该变量通过循环更改其值 - 因此,如果在“原始”迭代完成后执行从lambda表达式创建的委托,您将看到来自“当前”迭代的值。

一个简单的解决方法是在循环中声明和初始化迭代变量的副本,并捕获:

foreach (var item in OriginalItems) { var copy = item; Deployment.Current.Dispatcher.BeginInvoke(() => { CopyOfItems.Add(copy); }); // I feel sooo sleepy }

有关详细信息,请参阅Eric Lippert的博文“关闭循环变量被认为有害” 。

顺便说一下,你的真实代码是否真的在循环中做任何工作 ? 除了将UI线程工作分成几个块之外,你还真正使用线程来做任何重要事情并不清楚 - 这可以在没有BackgroundWorker情况下完成。

This is a known wrinkle in C# - and actually one which is being fixed in C# 5. When you capture the loop variable from a foreach loop in a lambda expression, you're capturing one variable. That variable changes its value through the loop - so if you execute the delegate created from the lambda expression after the "original" iteration as completed, you'll see the value from the "current" iteration instead.

A simple work around is to declare and initialize a copy of the iteration variable in the loop, and capture that:

foreach (var item in OriginalItems) { var copy = item; Deployment.Current.Dispatcher.BeginInvoke(() => { CopyOfItems.Add(copy); }); // I feel sooo sleepy }

See Eric Lippert's blog post "Closing over the loop variable considered harmful" for more details on this.

Does your real code actually do any work in the loop, by the way? It's not clear that you're really using threading to do anything significant other than splitting the UI thread work into several chunks - which can be done without a BackgroundWorker.

更多推荐

本文发布于:2023-08-03 14:01:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1391383.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:线程   好主意   列表   Thread   idea

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!