Вставить 100000 записей в MySQL с задачами - C#

У меня проблемы с моим кодом. Я пытаюсь вставить около 100 000 элементов в таблицу Mysql, используя Задачи, чтобы ускорить процесс. Вот мой код:

List < Task > tasks = new List < Task > ();
int counter = 0;
foreach(var folder in dirs) {
    object lockTarget = new object();

    tasks.Add(Task.Factory.StartNew(() => {
        try {
                comm.CommandText = "INSERT INTO webdata(url,title) VALUES(?sUrl,?sTitle,) ON DUPLICATE KEY UPDATE url=?sUrl,title=?sTitle";
                comm.Parameters.Add("?sUrl", MySql.Data.MySqlClient.MySqlDbType.VarChar).Value = url;
                comm.Parameters.Add("?sTitle", MySql.Data.MySqlClient.MySqlDbType.VarChar).Value = title;

                var mysql_return = comm.ExecuteNonQueryAsync();

                lock(lockTarget) {
                    counter++;
                    Console.WriteLine("\rProcessing {0} of {1} - {2} {3}", counter, dirs.Length, folder, mysql_return.Status);
                }

        } catch (MySql.Data.MySqlClient.MySqlException ex) {
            Console.WriteLine(ex.Message);
        }    
    }));
}

Task.Factory.StartNew(() => {
    Task.WaitAll(tasks.ToArray());
    Console.WriteLine("Finished");
    conn.Close();
});

Итак, когда я запускаю свой код, некоторые из задач (mysql_return) возвращаются rantocompletion и немного FaultedТаким образом, только половина моих записей фактически вставлена ​​в БД.

Я мог бы использовать ExecuteNonQuery и нет Task но потребуется много времени, чтобы вставить так много данных. Это проблема из-за аппаратного обеспечения (процессор не справляется с тысячами порожденных задач) или из-за моего кода?

Есть идеи? заранее спасибо

1 ответ

Решение

Проблема1: comm модифицируется в нескольких потоках, кажется, это должна быть локальная переменная.

Проблема 2: Вы не ждете задачи, возвращенной ExecuteNonQueryAsync и поэтому Task вернулся StartNew не буду ждать завершения ExecuteNonQueryAsync быть законченным.

В конце концов вы закрываете соединение, предполагая, что все сделано, но это не так. Все они запущены, но не завершены.

Вам нужно использовать дождаться результата ExecuteNonQueryAsync(для этого использования async лямбда) а также звоните Task.UnWrap или использовать Task.Run что дает вам UnWrap бесплатно.

Таким образом, ваш код станет примерно таким:

tasks.Add(Task.Run(async () => //Note Task.Run and async lambda
 {
      try
      {
        var comm = new WhateverCommand();
        ...

        var mysql_return = await comm.ExecuteNonQueryAsync();//Note the await
        ...
      }
      catch (MySql.Data.MySqlClient.MySqlException ex) 
      {
        Console.WriteLine(ex.Message);
      }    
}));
Другие вопросы по тегам