C#警惕匿名方法造成的变量共享实例分析

2019-12-26 14:11:13于丽

每次从数据源中读取数据后,添加到batchItems列表中,当batchItems满1000条时便进行一次提交。这段代码功能运行正常,可惜时间卡在了数据库提交上。数据的获取和处理很快,但是提交一次就要花较长时间。于是想想,数据提交和数据处理不会有资源上的冲突,那么就把数据提交放在另外一个线程上进行处理吧!于是,使用ThreadPool来改写代码:

 

  1. static void Process()  {  
  2. List<Item> batchItems = new List<Item>();  foreach (var item in ...) 
  3. {  batchItems.Add(item); 
  4. if (batchItems.Count > 1000)  { 
  5. ThreadPool.QueueUserWorkItem((o) =>  { 
  6. DataContext db = new DataContext();  db.Items.InsertAllOnSubmit(batchItems); 
  7. db.SubmitChanges();  }); 
  8. batchItems = new List<Item>();  } 
  9. }  } 

现在,我们将数据提交操作交给ThreadPoll执行,当线程池中有额外线程时,就会发起数据提交操作。而数据提交操作不会阻塞数据处理,因此按照那位兄弟的意图,数据会不断进行处理,最后只要等待所有数据库提交完成就可以了。思路很好,可惜运行时发现,原本(不利用多线程时)运行正常的代码,如今会“莫名其妙”地抛出异常。更为奇怪的是,数据库中的数据出现了丢失的情况:处理了并“提交”了一百万条数据,但是数据库里却少了一部分。于是对着代码左看右看,百思不得其解。

您看出问题原因来了吗?

分析原因

要发现问题所在,我们必须了解匿名方法在.NET环境中的实现方式。