m0f*_*0fo 21 .net c# parallel-processing multithreading entity-framework
我有一个ID列表,我需要在每个ID上运行几个存储过程.
当我使用标准的foreach循环时,它工作正常,但是当我有很多记录时,它的工作速度很慢.
我想将代码转换为使用EF,但我得到一个例外:"底层提供程序在Open上失败".
我在Parallel.ForEach中使用此代码:
using (XmlEntities osContext = new XmlEntities())
{
//The code
}
Run Code Online (Sandbox Code Playgroud)
但它仍然抛出异常.
知道如何使用与EF并行?我是否需要为我正在运行的每个程序创建一个新的上下文?我有大约10个程序,所以我认为创建10个上下文非常糟糕,每个上下文一个.
cas*_*One 38
实体框架使用的基础数据库连接不是线程安全的.你将需要在另一个线程,你要执行为每个操作的新的上下文.
您对如何并行化操作的关注是有效的; 开启和关闭的许多背景都很昂贵.
相反,您可能想要反思您对并行化代码的看法.看起来你正在循环遍历许多项目,然后为每个项目串行调用存储过程.
如果可以,为每个过程创建一个新的Task<TResult>
(或者Task
,如果您不需要结果),然后在其中,打开一个上下文,遍历所有项,然后执行存储过程.这样,您只有许多上下文等于并行运行的存储过程的数量.Task<TResult>
假设你有MyDbContext
两个存储过程,DoSomething1
并且两个存储过程DoSomething2
都是一个类的实例MyItem
.
实现上述内容将类似于:
// 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.
Run Code Online (Sandbox Code Playgroud)
如果你不能并行执行存储过程(每个存储过程都依赖于以特定顺序运行),那么你仍然可以并行化你的操作,它只是稍微复杂一些.
您将看到在项目中创建自定义分区(使用类上的静态Create
方法).这将为您提供获得实现的方法(注意,这不是你不能超过它).Partitioner
IEnumerator<T>
IEnumerable<T>
foreach
对于每个IEnumerator<T>
返回的实例,您将创建一个新实例Task<TResult>
(如果需要结果),并且在Task<TResult>
正文中,您将创建上下文,然后遍历由它返回的项IEnumerator<T>
,按顺序调用存储过程.
这看起来像这样:
// 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();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
36175 次 |
最近记录: |