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

начиная с исходного потока (многопоточность с Linq to SQL) стал довольно старым к настоящему времени, я думал, что опубликую еще один вопрос по аналогичной теме. Рассмотрим сценарий, в котором DomainService предоставляет множество методов для извлечения данных из базы данных SQL Server. Очевидно, что в многопользовательском сценарии с несколькими запросами, поступающими одновременно, этого следует ожидать.DataContext будет использоваться параллельно, без контроля и дополнительных усилий со стороны разработчика обрабатывать несколько запросов. Так почему же, если я помещаю свои последовательные запросы LINQ в параллель.Вызова(), весь ад вырывается на свободу, и я получаю dreadded " С этой командой уже связан открытый DataReader, который должен быть закрыт первым." ошибка ...?

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

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());

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

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

2 ответов


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

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

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


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