Написание таблицы Azure с использованием процесса против потоков

#c# #parallel-processing #task

#c# #параллельная обработка #задача

Вопрос:

Я записываю огромное количество данных в таблицу Azure из консольного приложения на C #. Это приводит к следующему

  1. Откройте соединение с уже существующей таблицей.
  2. Считывает файл с помощью StreamReader
  3. Собирает 100 запросов одновременно и выполняет пакетную запись в таблицу.

Скорость записи одного процесса составляет около 500-700 в секунду без распараллеливания, а для записи 1 миллиарда записей потребуется около 30 дней. Я сделал следующее для оптимизации:

  1. Создал 20 процессов, выполняющих вышеупомянутый exe-файл, и это выполнялось параллельно без каких-либо проблем, сократив время записи до 1,5 дня. [Идеальный сценарий, который я, к сожалению, не могу выполнить из-за ограничений в нашей кодовой базе]

6 ядер / 12 логических процессоров:

---------- --------------------------------- -------- ------------------------------------
| #process | Time per process per 10k writes | W/s | Total time in hours (1.3b queries) |
---------- --------------------------------- -------- ------------------------------------
| 2 | 14.2s/10k | 1408/s | 256h |
| 4 | 14.5s/10k | 2758/s | 130h |
| 6 | 14.6s/10k | 4109/s | 87h |
| 8 | 15s/10k | 5333/s | 65h |
| 12 | 16.1s/10k | 7453/s | 48h |
| 16 | 17.9s/10K | 8888/s | 42h |
| 18 | 19s/10k | 9473/s | 38h |
| 20 | 21.37s/10k | 9358/s | 39h |
---------- --------------------------------- -------- ------------------------------------

  1. логический процессор core / 1 занял почти столько же времени. Как уже отмечалось, время записи линейно увеличивается с увеличением количества процессов и, как ни странно, не зависит от количества ядер и логических процессоров. У таблиц Azure максимальная скорость ввода-вывода составляет около 20 тыс. в секунду.

  2. Создайте набор из 20 задач в консольном приложении. Это было неоптимально, и производительность ухудшалась по мере уменьшения количества ядер или увеличения количества потоков. Наилучшая производительность наблюдалась для двух задач. Я попытался изменить минимальный лимит в ThreadPool, но это ничего не изменило. ThreadPool.SetMinThreads(20, 20);

Код:

 foreach (var index in processIndex)
{
    Task t = Task.Run(() => 
    {
        //gets the appropriate file to read and write to table
        string currentFile = string.Format(outFileFormat, index);
        Service service = new Service(currentFile);
        service.JustReadFile();
    });
    tasks.Add(t);
}
tasks.WaitAll();
  

Производительность:

  -------- -------- ------------------------------------ 
| #tasks |  W/s   | Total time in hours (1.3b queries) |
 -------- -------- ------------------------------------ 
|      2 | 1408/s | 256h                               |
|     16 | ~800/s | ~488h                              |
|     18 | ~800/s | ~488h                              |
|     20 | ~800/s | ~488h                              |
 -------- -------- ------------------------------------ 
  

В приведенном выше коде все, что я делаю, это считываю файл для соответствующей задачи. Каждой задаче предварительно назначен файл для чтения. Здесь не выполняется запись в таблицу Azure, и это само по себе снижает производительность при увеличении числа задач. Я подумал, что, возможно, задачи конкурируют за ресурсы или при переключении контекста слишком много накладных расходов. Поскольку каждая задача имеет свой собственный объект Service, я полагаю, что это может быть не так. Я также думаю, что чтение файлов и создание объектов — это задача с интенсивным вводом-выводом, но если с этим могут справиться 20 процессов, то и 20 задач тоже?

Что здесь происходит и как я могу решить это с помощью потоков / задач?

Спасибо!

Комментарии:

1. На этот вопрос трудно ответить, потому что мы почти ничего не знаем. Почему вы используете таблицы Azure вместо Sql или Cosmos? Это одноразовая массовая вставка или вы делаете это каждую минуту, час или день? Кто получает доступ к этим данным после их записи?

2. Это запланировано на месяц. В первый раз было бы около ~ 1 миллиарда строк, а в последующие — по 100 миллионов каждый месяц. К этим данным будут обращаться несколько внутренних команд в своих приложениях, которые подключены к Интернету. Отсюда необходимость быстрого чтения с использованием таблицы Azure. Что-нибудь, что я могу добавить для большей ясности?

3. Я ничего не могу обещать, но взгляните на эту старую кэшированную версию некоторой справки