У меня есть многопоточное приложение, которое общается с SQL-сервером через Linq to Sql. Приложение нормально работает на четырехъядерном компьютере (Intel I-7), когда количество потоков искусственно поддерживается на уровне 8:
Parallel.ForEach(allIds,
new ParallelOptions { MaxDegreeOfParallelism = 8 },
x => DoTheWork(x));
Когда количество потоков остается на усмотрение системы:
Parallel.ForEach(allIds, x => DoTheWork(x));
По прошествии некоторого времени я получаю следующее исключение:
Истекло время ожидания. Период тайм-аута истек до получения соединения из пула. Это могло произойти из-за того, что все соединения в пуле использовались и был достигнут максимальный размер пула.
В моем приложении всего два шаблона для вызова SQL:
первый:
using (var dc = new MyDataContext())
{
//do stuff
dc.SafeSubmitChanges();
}
второй:
using (var dc = new MyDataContext())
{
//do some other stuff
DoStuff(dc);
}
.....
private void DoStuff(DataContext dc)
{
//do stuff
dc.SafeSubmitChanges();
}
Я решил задросселировать вызовы с помощью такой логики:
public static class DataContextExtention
{
public const int SQL_WAIT_PERIOD = 5000;
public static void SafeSubmitChanges(this DataContext dc)
{
try
{
dc.SubmitChanges();
}
catch (Exception e)
{
if (e.Message ==
"Timeout expired. The timeout period elapsed prior to obtaining a connection from the pool. This may have occurred because all pooled connections were in use and max pool size was reached.")
{
System.Data.SqlClient.SqlConnection.ClearAllPools();
System.Threading.Thread.Sleep(SQL_WAIT_PERIOD);
dc.SafeSubmitChanges();
}
else
{
throw;
}
}
}
}
Это не имело абсолютно никакого значения. Как только приложение генерирует первое исключение такого типа, все виды случайных мест в приложении (даже строки кода, не имеющие ничего общего с SQL-сервером) начинают генерировать это исключение.
Q1: Разве не предполагается, что использование оператора using с религиозной точки зрения защищает именно от этого сценария?
Q2: Что не так и как это исправить?
Примечание. Существует около 250 000 идентификаторов. Я также тестировал на MaxDegreeOfParallelism = 16
, и у меня такое же исключение.
e.Message
с постоянной строкой вместо проверки типа e? Это недопустимо, тем более что исключение может быть создано на любом языке. - person Tarec   schedule 14.05.2014foreach
? Вероятно, что по какой-то причине вы удаляетеDataContext
, но соединение не закрывается. Посмотрим, сможешь ли ты поместитьdc.Connection.Close()
в блокusing
. - person Evan L   schedule 14.05.2014MaxDegreeOfParallelism
значение 100, посмотрите, работает ли это, а затем попробуйте 101 и посмотрите, не удастся ли это. Даже если вашиDataContext
правильно утилизируются (а я думаю, что это так), после того, как вы исчерпали пул соединений, дополнительные контексты должны ждать освобождения соединения. Поскольку время ожидания операций с базой данных относительно велико, вполне возможно, чтоParallel.ForEach
выполняет более 100 одновременных операций. - person hatchet - done with SOverflow   schedule 19.05.2014Min Pool Size = 16
и проведите тест с 16 степенями параллелизма. Кроме того, проверьте возможность того, что Sql Server ограничивает соединения stackoverflow.com/questions/1499718/ - person hatchet - done with SOverflow   schedule 19.05.2014