#multithreading #entity-framework #iqueryable #task-parallel-library #objectcontext
#многопоточность #entity-framework #iqueryable #задача-параллельная-библиотека #objectcontext
Вопрос:
Я пытался обновить производительность своего кода в отношении запросов к базе данных. Проблема, с которой я в настоящее время сталкиваюсь, заключается в том, что, похоже, я не могу найти способ получить новый контекст для каждого подзапроса.
Использование приведенного ниже упрощенного кода приведет к непоследовательному появлению сообщения «Сбой базового поставщика при открытии».
using (var context = getNewContextObject())
{
var result = new SomeResultObject();
var parentQuery = context.SomeTable.Where(x => x.Name = "asdf");
Parallel.Invoke(() =>
{
result.count1 = parentQuery.Where(x => x.Amount >= 100 amp; x.Amount < 2000).Count();
}, () =>
{
result.count2 = parentQuery.Where(x => x.Amount < 100).Count();
}
, () =>
{
result.count3 = parentQuery.Where(x => x.Amount >= 2000).Count();
}
);
}
Пока единственным способом обойти это, по-видимому, является перестроение всего запроса для каждого подзапроса с новым контекстом. Есть ли какой-либо способ избежать построения каждого запроса снизу вверх с новым контекстом? Могу ли я вместо этого просто присоединять каждый запрос подзапроса к новому контексту? Я ищу что-то вроде приведенного ниже.
Parallel.Invoke(() =>
{
var subQuery = parentQuery.Where(x => x.Amount >= 100 amp; x.Amount < 2000).Count();
subQuery.Context = getNewContextObject();
result.count1 = subQuery.Count();
}, () =>
{
var subQuery = parentQuery.Where(x => x.Amount < 100).Count();
subQuery.Context = getNewContextObject();
result.count2 = subQuery.Count();
}
, () =>
{
var subQuery = parentQuery.Where(x => x.Amount >= 2000).Count();
subQuery.Context = getNewContextObject();
result.count3 = subQuery.Count();
}
);
}
Ответ №1:
Я не уверен, как именно это связано с вашей проблемой, но ни одна из функций EF не является потокобезопасной, поэтому я ожидаю, что параллельное выполнение нескольких запросов к одному экземпляру контекста может привести к сбоям по любой причине. Например, они обращаются к одному и тому же свойству соединения в контексте, но потоки не знают друг о друге, поэтому они могут закрыть соединение с другим потоком или заменить экземпляр другим экземпляром соединения (вы можете попытаться открыть соединение вручную перед запуском параллельных потоков и закрыть его, как только все потоки будут выполнены, но это не обязательно должно быть единственной проблемой).
Комментарии:
1. Это именно та проблема; Для работы OP потребуется 3 объекта контекста, или, как вы предлагаете, вручную открыть соединение и закрыть … но я все равно чувствовал бы себя лучше в отношении 3 контекстов или объектов подключения.