Я собрал небольшой тестовый жгут для диагностики того, почему пропускная способность моего приложения обработки данных C# (его основная функция выбирает записи в партиях 100 с удаленного сервера базы данных с использованием неблокирующего IO и выполняет простую обработку на них) ниже, чем это могло бы быть. Я заметил, что во время работы приложение не сталкивается с узкими местами на пути CPU (< 3%), сетевым или дисковым IO или оперативной памятью и не подчеркивает сервер базы данных (набор данных в базе данных почти всегда полностью ОЗУ). Если я запускаю несколько экземпляров приложения параллельно, я могу получить до ~ 45 экземпляров с только 10% -ной деградацией задержек, но с 45-кратным увеличением пропускной способности, прежде чем загрузка процессора на сервере базы данных станет узким местом (на тот момент, там до сих пор нет узких мест в ресурсах на клиенте).Почему пропускная способность этого приложения для обработки данных C# намного ниже, чем необработанные возможности сервера?
Мой вопрос: почему TPL не увеличивает количество задач в полете или иным образом увеличивает пропускную способность, когда клиентский сервер способен существенно повысить пропускную способность?
Упрощенный фрагмент кода:
public static async Task ProcessRecordsAsync()
{
int max = 10000;
var s = new Stopwatch();
s.Start();
Parallel.For(0, max, async x =>
{
await ProcessFunc();
});
s.Stop();
Console.WriteLine("{2} Selects completed in {0} ms ({1} per ms).", s.ElapsedMilliseconds, ((float)s.ElapsedMilliseconds)/max, max);
}
public static async Task ProcessFunc()
{
string sql = "select top 100 MyTestColumn from MyTestTable order by MyTestColumn desc;";
string connStr = "<blah>...";
using (SqlConnection conn = new SqlConnection(connStr))
{
try
{
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
DbDataReader rdr = await cmd.ExecuteReaderAsync();
while (rdr.Read())
{
// do simple processing here
}
rdr.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
Запустите профайлер с кодом, чтобы увидеть код, который использует больше всего времени, а затем определите, следует ли вам оптимизировать этот код. –
@RudyTheHunter, это неблокирующие вызовы базы данных, которые занимают больше всего времени, но на клиентском компьютере практически не нужны ресурсы и должны легко распараллеливаться, что подтверждается тем фактом, что я могу запускать 45 экземпляров приложения, не сталкиваясь с какими-либо узкими местами ресурсов на клиент. Я пытаюсь понять, почему я не могу получить такую же степень распараллеливания в одном процессе. – Dan
Кажется, что каждый раз выбирает один и тот же самый 100 строк из базы данных. Мне интересно, если вы снова и снова сталкиваетесь с теми же 100 рядами. Вы сказали, что делаете неблокирующие вызовы базы данных, но делаете им простые обновления. Вам нужно выбрать более 100 строк в качестве лучшего примера? Я думаю, вам нужно поделиться более подробными сведениями о том, что происходит в этом процессе. –