Многопоточность с 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
через потоки. Это изначально небезопасно. Кроме того, DataContext
s предназначены для использования по одному на единицу работы (т. е. по одному на разговор). Каждый запрос должен рассматриваться как отдельный разговор и отвечать уникальным DataContext
.