The underlying database connections that the Entity Framework are using are not thread-safe. Usted tendrá necesidad de crear un nuevo contexto para cada operación en otro hilo que va a realizar.
Su preocupación sobre cómo paralelizar la operación es válida; que muchos contextos van a ser costosos de abrir y cerrar.
En su lugar, es posible que desee invertir cómo piensa sobre la paralelización del código. Parece que está pasando por encima de una serie de elementos y luego llama a los procedimientos almacenados en serie para cada elemento.
Si es posible, crear un nuevo Task<TResult>
(o Task
, si usted no necesita un resultado) para cada procedimiento y entonces en ese Task<TResult>
, abre un solo contexto, recorrer todos los elementos, y luego ejecuta el procedimiento almacenado. De esta forma, solo tiene un número de contextos igual al número de procedimientos almacenados que está ejecutando en paralelo.
Supongamos que usted tiene una MyDbContext
con dos procedimientos almacenados, DoSomething1
y DoSomething2
, los cuales tienen una instancia de una clase, MyItem
.
ejecución de lo anterior sería algo como:
// You'd probably want to materialize this into an IList<T> to avoid
// warnings about multiple iterations of an IEnumerable<T>.
// You definitely *don't* want this to be an IQueryable<T>
// returned from a context.
IEnumerable<MyItem> items = ...;
// The first stored procedure is called here.
Task t1 = Task.Run(() => {
// Create the context.
using (var ctx = new MyDbContext())
// Cycle through each item.
foreach (MyItem item in items)
{
// Call the first stored procedure.
// You'd of course, have to do something with item here.
ctx.DoSomething1(item);
}
});
// The second stored procedure is called here.
Task t2 = Task.Run(() => {
// Create the context.
using (var ctx = new MyDbContext())
// Cycle through each item.
foreach (MyItem item in items)
{
// Call the first stored procedure.
// You'd of course, have to do something with item here.
ctx.DoSomething2(item);
}
});
// Do something when both of the tasks are done.
Si no puede ejecutar los procedimientos almacenados en paralelo (cada uno es dependiente de que se ejecute en un cierto orden), entonces usted puede todavía paraleliza tus operaciones, es solo un poco más complejo.
Miraría creating custom partitions en sus artículos (usando el Create
method estático en el Partitioner
class). Esto le dará los medios para obtener implementaciones de IEnumerator<T>
(tenga en cuenta que esto es noIEnumerable<T>
por lo que no puede foreach
sobre él).
Para cada instancia IEnumerator<T>
vuelvas, que crearía un nuevo Task<TResult>
(si necesita un resultado), y en el cuerpo Task<TResult>
, debe crear el contexto y luego desplazarse a través de los artículos devueltos por el IEnumerator<T>
, llamando los procedimientos almacenados en orden
Ese sería el siguiente:
// Get the partitioner.
OrdinalPartitioner<MyItem> partitioner = Partitioner.Create(items);
// Get the partitions.
// You'll have to set the parameter for the number of partitions here.
// See the link for creating custom partitions for more
// creation strategies.
IList<IEnumerator<MyItem>> paritions = partitioner.GetPartitions(
Environment.ProcessorCount);
// Create a task for each partition.
Task[] tasks = partitions.Select(p => Task.Run(() => {
// Create the context.
using (var ctx = new MyDbContext())
// Remember, the IEnumerator<T> implementation
// might implement IDisposable.
using (p)
// While there are items in p.
while (p.MoveNext())
{
// Get the current item.
MyItem current = p.Current;
// Call the stored procedures. Process the item
ctx.DoSomething1(current);
ctx.DoSomething2(current);
}
})).
// ToArray is needed (or something to materialize the list) to
// avoid deferred execution.
ToArray();
No soy un gurú de subprocesos múltiples, pero si está utilizando transacciones o su lectura/escritura se bloquea, es posible que no obtenga un mejor rendimiento que simplemente hacerlo en serie. – Matthew
Dudo martillar el servidor sql estresado con más hilos no ayudará al rendimiento ... – rene
El sql no está estresado en absoluto, por eso quiero usar un paralelo. y seguramente correrá más rápido. –