Многопоточность с Linq to SQL - PullRequest
       22

Многопоточность с Linq to SQL

6 голосов
/ 05 января 2011

Поскольку исходный поток ( Многопоточность с Linq to SQL ) к настоящему времени уже устарел, я решил опубликовать еще один вопрос на аналогичную тему. Рассмотрим сценарий, в котором DomainService предоставляет множество методов для извлечения данных из базы данных SQL Server. Очевидно, что в многопользовательском сценарии, когда несколько запросов поступают одновременно, следует ожидать, что this.DataContext будет использоваться параллельно, без какого-либо контроля или дополнительных усилий со стороны разработчика по обработке этих нескольких запросов. Так почему же, если я помещу свои последовательные запросы LINQ в Parallel.Invoke (), все прекратятся, и я получу ужас «С этой Командой уже связан открытый DataReader, который должен быть закрыт первым». 1004 * ошибка ...?

Чтобы продемонстрировать, это работает:

List<Data> retVal = new List<Data>();

retVal.AddRange(this.DataContext.Table1.Where(w=>w.A==1).Select(s=>new Data{f1=s.D}).ToList());
retVal.AddRange(this.DataContext.Table1.Where(w=>w.B==2).Select(s=>new Data{f1=s.D}).ToList());
retVal.AddRange(this.DataContext.Table1.Where(w=>w.C==3).Select(s=>new Data{f1=s.D}).ToList());

... а это не так:

List<Data> retVal = new List<Data>();
Parallel.Invoke(
()=>retVal.AddRange(this.DataContext.Table1.Where(w=>w.A==1).Select(s=>new Data{f1=s.D}).ToList()),
()=>retVal.AddRange(this.DataContext.Table1.Where(w=>w.B==2).Select(s=>new Data{f1=s.D}).ToList()),
()=>retVal.AddRange(this.DataContext.Table1.Where(w=>w.C==3).Select(s=>new Data{f1=s.D})).ToList());

Неважно на секунду, что List не является поточно-ориентированным, поскольку ошибка возникает из-за соединения данных SQL.

Любые идеи и объяснения будут высоко оценены.

Ответы [ 2 ]

10 голосов
/ 05 января 2011

Во-первых, чтобы уточнить, эта проблема связана с многопоточностью, а не с несколькими пользователями.В многопользовательском сценарии каждый пользователь будет иметь свой собственный экземпляр DataContext, избегая проблем с многопоточностью вокруг общих экземпляров.

Параллельный пример завершается ошибкой, поскольку DataContext не является потокобезопасным объектом;ожидается, что он будет использоваться одним потоком, а не многими параллельно.Это возникает как исключение, связанное со считывателями данных, потому что DataContext имеет открытое соединение, считывающее со считывателем данных, когда вы пытаетесь выполнить второе выражение параллельно.

Та же проблема будет очевидна, если выпопытался использовать один экземпляр SqlConnection в нескольких потоках без каких-либо методов сериализации.

8 голосов
/ 05 января 2011

Вы не должны делиться DataContext между потоками.Это по своей сути небезопасно.Кроме того, DataContext s предназначены для использования по одному на единицу работы (то есть по одному на разговор).Каждый запрос должен рассматриваться как отдельный разговор и должен отвечать уникальным DataContext.

...