将数据加载到SQL Server时出现C#多线程问题

时间:2014-04-03 14:10:09

标签: c# sql multithreading

我有一个约7030项的清单。我将列表中的项目保存到SQL Server中的表中。我想,我可以使用多线程来加速这个过程,但它出现了问题。

上传到数据库的项目数量没有变化,但是当我在运行我的代码后查询表格中的记录数量时,它总是不同的,比如一次它将上传6925,下次6831等。我不明白为什么会这样。

在我获取数据的课程中

 void DatabaseUploadMultiThreading()
    {
        DateTime dtUpload = Program.UploadDate();

        int numThread = 8;          
        int splitNum = _holdingList.Count / numThread;
        int leftOver = _holdingList.Count - (splitNum * (numThread - 1));

        DatabaseWriter[] dbArray = new DatabaseWriter[numThread];
        List<Holding>[] holdingArray = new List<Holding>[numThread];
        Task[] taskDB = new Task[numThread];

        for (int i = 0; i < holdingArray.Length; i++)
        {
            dbArray[i] = new DatabaseWriter(i + 1, dtUpload);

            if (i == (numThread - 1))
                holdingArray[i] = _holdingList.GetRange(i * splitNum, leftOver);
            else
                holdingArray[i] = _holdingList.GetRange(i * splitNum, splitNum);
        }

        for (int i = 0; i < taskDB.Length; i++)
            taskDB[i] = Task.Factory.StartNew(dbArray[i].UploadHoldings, holdingArray[i]);

        try
        {
            Task.WaitAll(taskDB);                   // wait for all the threads to complete
        }
        catch (AggregateException ex)
        {
            ExceptionDispatchInfo.Capture(ex.InnerException).Throw();
        }

    }

DatabaseWriter类snipet

 class DatabaseWriter : IDisposable
{
    #region variable declaration
    private SqlConnection _connection;
    private SqlCommand _command;
    private static readonly string _connectionString = "myConnectionString";

    public void UploadHoldings(object objHoldingList)
    {
        List<Holding> holdingList = (List<Holding>)objHoldingList;

        using (_connection = new SqlConnection(_connectionString))
        {
            _connection.Open();

            DataReImported(_dtUpload);

            for (int i = 0; i < holdingList.Count; i++)
            {
                string cmdText = "INSERT INTO HOLDINGS([FUND_CD], [SEDOLCHK], [NOMINAL], [CURR], [PRICE], [DATEU]) " +
                                    "VALUES(@fundcode, @sedol, @nominal, @curr, @price, @dtUpload)";

                _command = new SqlCommand(cmdText, _connection);
                _command.Parameters.Add("@fundCode", SqlDbType.VarChar).Value = holdingList[i].FundCode;
                _command.Parameters.Add("@sedol", SqlDbType.VarChar).Value = holdingList[i].IdSedol;
                _command.Parameters.Add("@nominal", SqlDbType.Decimal).Value = holdingList[i].Nominal;
                _command.Parameters.Add("@curr", SqlDbType.VarChar).Value = holdingList[i].Currency;
                _command.Parameters.Add("@price", SqlDbType.Decimal).Value = holdingList[i].Price;
                _command.Parameters.Add("@dtUpload", SqlDbType.Date).Value = _dtUpload;
                _command.ExecuteNonQuery();

                Console.WriteLine("Thread Number:" + _threadNum + " Security Number uploaded: " + i + " of " + holdingList.Count);
            }
            _connection.Close();
        }
    }



}

1 个答案:

答案 0 :(得分:1)

我建议这不是使用多个任务的最佳位置。您上面显示的代码效率有点低,并将其拆分为Task对象并并行运行它们,在许多情况下只会使它们在另一个上面发生绊倒并使您速度降低或导致其中一个不执行。就像三个傀儡都试图同时冲进一扇门一样。

执行基本的,明显的优化,就像上面提到的其他回答者一样,即只创建一次SqlCommand,并在循环中做一个绝对最小值(或者尝试批量加载方法)。并检查ExecuteNonQuery返回的值以验证写入的记录数。