SqlDataAdapter.Fill – enfoque asíncrono

Utilizando C # / .NET 3.5.

Actualmente estoy rellenando 2 DataTables una tras otra usando SqlDataAdapter.Fill ().

Quiero llenar estas dos tablas de datos en paralelo, al mismo tiempo haciendo cada una de forma asíncrona. Sin embargo, no hay una versión asíncrona del método Fill (), es decir, ¡BeginFill () sería genial!

Un enfoque que he probado es (pseudo):

  1. SqlCommand1.BeginExecuteReader // 1st consulta, para DataTable1
  2. SqlCommand2.BeginExecuteReader // 2ª consulta, para DataTable2
  3. SqlCommand1.EndExecuteReader
  4. SqlCommand2.EndExecuteReader
  5. DataTable1.Load (DataReader1)
  6. DataTable2.Load (DataReader2)

Sin embargo, DataTable.Load () lleva mucho tiempo:
Se tarda 3 segundos para hacer el paso 1 al paso 4.
El paso 5 luego toma 22 segundos.
El paso 6 tarda 17 segundos.
Entonces, combinamos 39 segundos para los pasos 5 y 6.

El resultado final es que esto no me da ningún beneficio si solo hago 2 SqlDataAdapter.Fills, uno después del otro. Quiero que el resultado neto sea que todo el proceso lleva solo el tiempo que sea la consulta más larga (o lo más cerca posible).

Buscar formas recomendadas para terminar con algo que sea realmente un enfoque asíncrono para llenar una tabla de datos.

¿O simplemente lo administro yo mismo y saco 2 hilos separados, cada uno de los cuales llena una tabla de datos?

Yo sugeriría tener un hilo de trabajo separado para cada uno. Podría usar ThreadPool.QueueUserWorkItem .

List events = new List(); 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()); 

Esto se debe a que DataTable tiene muchos objetos para crear (filas, valores). Debe hacer que la ejecución del adaptador y el llenado de una fuente de datos se realicen en un subproceso diferente y sincronizar la espera de que finalice cada operación antes de continuar.

El siguiente código fue escrito en el Bloc de notas y probablemente ni siquiera se comstack, pero espero que tengas la idea …

 // Setup state as a parameter object containing a table and adapter to use to populate that table here void DoWork() { List 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); }