SqlDataAdapter.Fill - 异步方法

时间:2010-01-21 11:50:06

标签: c# .net asynchronous datatable

使用C#/ .NET 3.5。

目前我正在使用SqlDataAdapter.Fill()依次填充2个DataTable。

我希望并行地填充这两个DataTable,同时异步执行每个DataTable。但是,没有Fill()方法的异步版本 - 即BeginFill()会很棒!

我尝试过的一种方法是(伪):

  1. SqlCommand1.BeginExecuteReader //第一个查询,适用于DataTable1
  2. SqlCommand2.BeginExecuteReader //第二个查询,适用于DataTable2
  3. SqlCommand1.EndExecuteReader
  4. SqlCommand2.EndExecuteReader
  5. DataTable1.Load(DataReader1)
  6. DataTable2.Load(DataReader2)
  7. 但是,DataTable.Load()需要很长时间:
    步骤1到步骤4需要3秒钟 步骤5然后需要22秒。
    第6步需要17秒 因此,步骤5和6合并了39秒。

    最终的结果是,这让我没有任何好处而只是一个接一个地做2个SqlDataAdapter.Fills。我希望最终结果是整个过程只需要最长的查询(或尽可能接近)。

    寻找推荐的方法,最终得到一些真正的异步方法来填充DataTable。

    或者我自己管理它并滚动2个单独的线程,每个线程填充一个DataTable?

2 个答案:

答案 0 :(得分:5)

我建议每个人都有一个单独的工作线程。您可以使用ThreadPool.QueueUserWorkItem

List<AutoResetEvent> events = new List<AutoResetEvent>();

AutoResetEvent loadTable1 = new AutoResetEvent(false);
events.Add(loadTable1);
ThreadPool.QueueUserWorkItem(delegate 
{ 
     SqlCommand1.BeginExecuteReader;
     SqlCommand1.EndExecuteReader;
     DataTable1.Load(DataReader1);
     loadTable1.Set();
});

AutoResetEvent loadTable2 = new AutoResetEvent(false);
events.Add(loadTable2);
ThreadPool.QueueUserWorkItem(delegate 
{ 
     SqlCommand2.BeginExecuteReader;
     SqlCommand2.EndExecuteReader;
     DataTable2.Load(DataReader2);
     loadTable2.Set();
});

// wait until both tables have loaded.
WaitHandle.WaitAll(events.ToArray());

答案 1 :(得分:1)

这是因为DataTable有很多要创建的对象(行,值)。您应该在不同的线程中完成适配器的执行和数据表的填充,并在继续之前同步等待每个操作完成。

以下代码是用记事本编写的,可能甚至没有编译,但希望你能得到这个想法......

// Setup state as a parameter object containing a table and adapter to use to populate that table here

void DoWork()
{
    List<AutoResetEvent> signals = GetNumberOfWaitHandles(2);

    var params1 = new DataWorkerParameters
        {
            Command = GetCommand1();
            Table = new DataTable();
        }

    var params2 = new DataWorkerParameters
        {
            Command = GetCommand2();
            Table = new DataTable();
        }

    ThreadPool.QueueUserWorkItem(state => 
        {
            var input = (DataWorkerParameters)state;
            PopulateTable(input);
            input.AutoResetEvent.Set(); // You can use AutoResetEvent.WaitAll() in the caller to wait for all threads to complete
        },
        params1
    );

    ThreadPool.QueueUserWorkItem(state => 
        {
            var input = (DataWorkerParameters)state;
            PopulateTable(input);
            input.AutoResetEvent.Set(); // You can use AutoResetEvent.WaitAll() in the caller to wait for all threads to complete
        },
        params2
    );

    WaitHandle.WaitAll(signals.ToArray());
}


void PopulateTable(DataWorkerParameters parameters)
{
    input.Command.ExecuteReader();
    input.Table.Load(input.Command);
}