使用Linq to SQL进行multithreading处理
我正在构建一个应用程序,它要求我使用DataContext的内部线程。 我的应用程序不断抛出InvalidOperationException
类似于:
There is already an open DataReader associated with this Command which must be closed first
ExecuteReader requires an open and available Connection. The connection's current state is connecting
这些例外是间歇性的。
这是我的代码片段:
var repo = new Repository(); var entities = repo.GetAllEntities(); foreach (var entity in entities) { ThreadPool.QueueUserWorkItem( delegate { try { ProcessEntity(entity); } catch (Exception) { throw; } }); }
我认为将一个实体传递给主线程中的一个线程可能会有一些问题,因为一旦我尝试访问entity
的属性,错误似乎就会抛出。
任何人都知道为什么会发生这种情况以及如何解决它?
更新
这是我决定采用的:
var events = new Dictionary(); var repo = new Repository(); var entities = repo.GetAllEntities(); foreach (var entity in entities) { events.Add(entity.ID, new AutoResetEvent(false)); ThreadPool.QueueUserWorkItem( delegate { var repo = new Repository(); try { ProcessHierarchy(repo.GetEntity(entity.ID), ReportRange.Weekly); } catch (Exception) { throw; } finally { events[entity.ID].Set(); } }); } WaitHandle.WaitAll(events.Values.ToArray());
欢迎改进/建议,但这似乎已经成功了。
抛出exception,因为实体的某些属性在先前的读取器尚未关闭时执行新查询。 您不能同时对数据上下文执行多个查询。
作为一种解决方法,您可以“访问”您在ProcessEntity()
访问的属性,并使SQL在该线程之前运行。
例如:
var repo = new Repository(); var entities = repo.GetAllEntities(); foreach (var entity in entities) { var localEntity = entity; // Verify the callback uses the correct instance var entityCustomers = localEntity.Customers; var entityOrders = localEntity.Orders; var invoices = entityOrders.Invoices; ThreadPool.QueueUserWorkItem( delegate { try { ProcessEntity(localEntity); } catch (Exception) { throw; } }); }
此解决方法将仅在主线程上执行SQL,并且处理将在其他线程中完成。 由于所有查询都在单个线程中完成,因此您在这里放松了一些效率。 如果ProcessEntity()
有很多逻辑并且查询不是很大,那么这个解决方案很好。
尝试在新线程中创建Repository而不是传入它。
请注意,SqlConnection实例不是线程安全的。 你是否仍然有一个开放的阅读器。 通常,从多个线程访问SqlConnection实例将导致不可预测的间歇性问题。
请参阅: http : //msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.aspx
我的解决方案是LightSpeed Persistence框架,它在8个实体之前是免费的。 每个线程创建单元。