.NET ArrayList 并行处理

发布于 2024-09-11 08:34:11 字数 668 浏览 2 评论 0原文

我第一次尝试嵌入多线程并遇到一些意想不到的问题,希望你能提供帮助。

这是给我带来麻烦的代码片段:

ArrayList recordsCollection = new ArrayList();
ArrayList batchCollection = null;
int idx = 0;

while(true)
{
  // Some code to generate and assign new batchCollection here
  recordsCollection.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate
  {
    ProcessCollection(recordsCollection.GetRange(idx, 1));
  });
  Interlocked.Increment(ref idx);
}

private void ProcessCollection(ArrayList collection)
{
   // Do some work on collection here
}

调用 Process Collection 方法并且我尝试迭代集合时,我收到“基础列表中的范围无效”。

提前致谢!

更新:伙计们,谢谢你们每一个人。通过采纳您的建议,我能够大大简化并使其发挥作用。

I am attempting at embedding multi-threading for the first time ever and running into some unexpected issues, hope you can help.

Here's the code fragment that gives me troubles:

ArrayList recordsCollection = new ArrayList();
ArrayList batchCollection = null;
int idx = 0;

while(true)
{
  // Some code to generate and assign new batchCollection here
  recordsCollection.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate
  {
    ProcessCollection(recordsCollection.GetRange(idx, 1));
  });
  Interlocked.Increment(ref idx);
}

private void ProcessCollection(ArrayList collection)
{
   // Do some work on collection here
}

Once the Process Collection method is invoked and I am attempting to iterate through collection I am getting "The range in the underlying list is invalid".

Thanks in advance!

Update: Guys, thank you to each and every one of you. Through applying your suggestions I was able to greatly simplify and get it to work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

放我走吧 2024-09-18 08:34:11

此处没有必要使用 Interlocked.Increment。您希望局部变量 idx 只能被一个线程看到,因此不需要锁定。

目前,您正在“关闭循环变量”,这意味着线程看到的是变量的最新值,而不是创建委托时的值。您希望其他线程接收此变量的副本。即使原始变量发生变化,这些副本也不会改变。

尝试将代码更改为:

int j = idx;
ThreadPool.QueueUserWorkItem(delegate
{
    ProcessCollection(recordsCollection.GetRange(j, 1));
});

相关问题

相关文章

Your use of Interlocked.Increment here is unnecessary. You want that the local variable idx is only be seen by one thread so there is no need to lock.

Currently you are "closing over the loop variable" which means that the threads see the latest value of the variable rather than the value at the time the delegate was created. You want the other threads to receive copies of this variable. These copies will then not change even if the original variable changes.

Try changing your code to this:

int j = idx;
ThreadPool.QueueUserWorkItem(delegate
{
    ProcessCollection(recordsCollection.GetRange(j, 1));
});

Related question:

Related article:

长途伴 2024-09-18 08:34:11

你有几个问题。

  • 就像马克指出的那样,您正在捕获一个循环变量,这真的会让事情变得混乱。
  • 您在修改集合的同时读取它,而无需使用同步机制。

我假设您省略了获取 batchCollection 的代码,然后为了简洁起见定期从 recordsCollection 中删除它们,否则也会出现问题。

以下是修复方法。

ArrayList recordsCollection = new ArrayList();  
ArrayList batchCollection = null;  
int idx = 0;  

while(true)  
{  
  lock (recordsCollection) 
  {
    recordsCollection.Add(batchCollection);  
  }

  int capturedIndex = idx; // Used for proper capturing.

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ArrayList range;
    lock (recordsCollection)
    {
      range = recordsCollection.GetRange(capturedIndex, 1);
    }
    ProcessCollection(range);  
  });  

  idx++;
}  

或者我的重构版本,据我所知,它做了完全相同的事情......

List<List<Record>> recordsCollection = new ArrayList();  
List<Record> batchCollection = null;  

while(true)  
{  
  recordsCollection.Add(batchCollection);

  List<List<Record>> range = new List<List<Record>>();
  range.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ProcessCollection(range);  
  });      
}  

You have a couple of problems.

  • Like Mark pointed out you are capturing a loop variable which will really confuse things here.
  • You are modifying the collection while at the same time reading it without the use of synchronization mechanisms.

I am assuming you have omitted the code for acquiring a batchCollection and then periodically removing them from recordsCollection for brevity, otherwise there would be issues there as well.

Here is how you can fix it.

ArrayList recordsCollection = new ArrayList();  
ArrayList batchCollection = null;  
int idx = 0;  

while(true)  
{  
  lock (recordsCollection) 
  {
    recordsCollection.Add(batchCollection);  
  }

  int capturedIndex = idx; // Used for proper capturing.

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ArrayList range;
    lock (recordsCollection)
    {
      range = recordsCollection.GetRange(capturedIndex, 1);
    }
    ProcessCollection(range);  
  });  

  idx++;
}  

Or my refactored version which, as best I can tell anyway, does the exact same thing...

List<List<Record>> recordsCollection = new ArrayList();  
List<Record> batchCollection = null;  

while(true)  
{  
  recordsCollection.Add(batchCollection);

  List<List<Record>> range = new List<List<Record>>();
  range.Add(batchCollection);

  ThreadPool.QueueUserWorkItem(delegate  
  {
    ProcessCollection(range);  
  });      
}  
童话里做英雄 2024-09-18 08:34:11

你在这里玩火。
您有一个开放的闭包,请参阅:http://en.wikipedia.org/wiki/Closure_ (computer_science)

另外,如果您只获取一项,为什么还要使用 getRange ?

使用通用列表也可能有所帮助。

    private void wee()
    {
        List<List<string>> recordsCollection = new List<List<string>>();

        //int idx = 0;

        while(true)
        {
            //scope the batchcollection here if you want to start a thread with an anonymous delegate
            List<string> batchCollection = null;
            // Some code to generate and assign new batchCollection here
            recordsCollection.Add(batchCollection);

              ThreadPool.QueueUserWorkItem(delegate
              {
                  ProcessCollection(batchCollection);
              });
              //Interlocked.Increment(ref idx);
        }
    }
    private void ProcessCollection(List<string> collection)
    {
        // Do some work on collection here
    }

如果我错了,请纠正我,但我认为您不再需要 idx 变量。

另外,不要忘记异常是由调用堆栈引发的: http://www .codeproject.com/KB/architecture/exceptionbestpractices.aspx

干杯!

You are playing with fire here.
You got an open closure, see : http://en.wikipedia.org/wiki/Closure_(computer_science)

Also, why you use getRange if you are only getting one item ?

Using a generic list could also help.

    private void wee()
    {
        List<List<string>> recordsCollection = new List<List<string>>();

        //int idx = 0;

        while(true)
        {
            //scope the batchcollection here if you want to start a thread with an anonymous delegate
            List<string> batchCollection = null;
            // Some code to generate and assign new batchCollection here
            recordsCollection.Add(batchCollection);

              ThreadPool.QueueUserWorkItem(delegate
              {
                  ProcessCollection(batchCollection);
              });
              //Interlocked.Increment(ref idx);
        }
    }
    private void ProcessCollection(List<string> collection)
    {
        // Do some work on collection here
    }

Correct me if i'm wrong, but I do not think you will need the idx variable anymore.

Also, don't forget that exceptions are throw on by call stack : http://www.codeproject.com/KB/architecture/exceptionbestpractices.aspx

Cheers !

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文