Para acelerar las cosas que usted debe utilizar las operaciones en bloque (Transacciones grupo de entidades), lo que le permite comprometerse hasta 100 artículos dentro de una única solicitud:
foreach (var item in myItemsToAdd)
{
this.Context.AddObject(TableName, item);
}
this.Context.SaveChanges(SaveChangesOptions.Batch);
Esto se puede combinar con Partitioner.Create (+ AsParallel) para enviar solicitudes múltiples en diferentes hilos/núcleos por lote de 100 elementos para hacer las cosas realmente rápido.
Pero antes de hacer todo esto, read through the limitations de usar transacciones por lotes (100 elementos, 1 partición por transacción, ...).
Actualización:
Dado que no se puede utilizar transacciones Éstos son algunos otros consejos. Eche un vistazo a this MSDN thread para mejorar el rendimiento al usar el almacenamiento de tablas. Escribí algo de código para mostrar la diferencia:
private static void SequentialInserts(CloudTableClient client)
{
var context = client.GetDataServiceContext();
Trace.WriteLine("Starting sequential inserts.");
var stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 1000; i++)
{
Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId));
context.AddObject(TABLENAME, new MyEntity()
{
Date = DateTime.UtcNow,
PartitionKey = "Test",
RowKey = Guid.NewGuid().ToString(),
Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString())
});
context.SaveChanges();
}
stopwatch.Stop();
Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString());
}
Así, la primera vez que ejecute esta me da el siguiente resultado:
Starting sequential inserts.
Adding item 0. Thread ID: 10
Adding item 1. Thread ID: 10
..
Adding item 999. Thread ID: 10
Done in: 00:03:39.9675521
Se tarda más de 3 minutos y añadir artículos 1000. Ahora, he cambiado el app.config en función de las extremidades en el foro de MSDN (maxconnection debe ser de 12 * número de núcleos de CPU):
<system.net>
<settings>
<servicePointManager expect100Continue="false" useNagleAlgorithm="false"/>
</settings>
<connectionManagement>
<add address = "*" maxconnection = "48" />
</connectionManagement>
</system.net>
Y después de ejecutar la aplicación de nuevo me sale esta salida:
Starting sequential inserts.
Adding item 0. Thread ID: 10
Adding item 1. Thread ID: 10
..
Adding item 999. Thread ID: 10
Done in: 00:00:18.9342480
De más de 3 minutos a 18 segundos. ¡Que diferencia! Pero podemos hacerlo aún mejor. Aquí hay un código inserta todos los elementos usando una Partitioner (inserciones sucederán en paralelo):
private static void ParallelInserts(CloudTableClient client)
{
Trace.WriteLine("Starting parallel inserts.");
var stopwatch = new Stopwatch();
stopwatch.Start();
var partitioner = Partitioner.Create(0, 1000, 10);
var options = new ParallelOptions { MaxDegreeOfParallelism = 8 };
Parallel.ForEach(partitioner, options, range =>
{
var context = client.GetDataServiceContext();
for (int i = range.Item1; i < range.Item2; i++)
{
Trace.WriteLine(String.Format("Adding item {0}. Thread ID: {1}", i, Thread.CurrentThread.ManagedThreadId));
context.AddObject(TABLENAME, new MyEntity()
{
Date = DateTime.UtcNow,
PartitionKey = "Test",
RowKey = Guid.NewGuid().ToString(),
Text = String.Format("Item {0} - {1}", i, Guid.NewGuid().ToString())
});
context.SaveChanges();
}
});
stopwatch.Stop();
Trace.WriteLine("Done in: " + stopwatch.Elapsed.ToString());
}
Y el resultado:
Starting parallel inserts.
Adding item 0. Thread ID: 10
Adding item 10. Thread ID: 18
Adding item 999. Thread ID: 16
..
Done in: 00:00:04.6041978
Voila, de 3m39s que cayó a 18 años y ahora incluso caer a 4s.
¿Está llamando por casualidad toda esa lógica con CreateTableIfNotExist() en un bucle? o solo Add/SaveChanges() en un bucle? CreateTableIfNotExist() no es una llamada barata y desea omitirla si no es necesaria – Igorek
Este código se ejecuta para cada solicitud. Tienes razón, es caro llamar a CreateTableIfNotExist en cualquier momento. Intentaré eliminarlo y lo haré solo si la tabla no existe error. – gabba