我正在使用nopCommerce。我已经使用GetProudctsByIds获得了多少产品。从那时起,我需要使用CustomClass映射某些实体。 我觉得实体映射过程非常慢,而产品数量大于特定数量,所以我想通过并行运行加速这个过程,我决定使用任务并行库。
例如,
var products = _productService.GetProductsByIds(productIds);
//sequential foreach
//This works fine.
foreach(var product in products)
{
var obj = new CustomProduct();
obj.Id = product .Id;
obj.Name = product .Name;
obj.ShortDescription = product .ShortDescription;
obj.FullDescription = product .FullDescription;
//Get Product URL
var picture = _pictureService.GetPicturesByProductId(product .Id, 1).FirstOrDefault();
if (picture != null)
{
obj.ImageUrl = _pictureService.GetPictureUrl(picture, _mediaSetting.ProductThumbPictureSize, true);
}
//there are many more entities are mapping here…
objList.Add(obj);
}
//parallelized foreach
Parallel.ForEach(products, (product, state) =>
{
var obj = new CustomProduct();
obj.Id = product .Id;
obj.Name = product .Name;
obj.ShortDescription = product .ShortDescription;
obj.FullDescription = product .FullDescription;
//Get Product URL
var picture = _pictureService.GetPicturesByProductId(product .Id, 1).FirstOrDefault();
if (picture != null)
{
obj.ImageUrl = _pictureService.GetPictureUrl(picture, _mediaSetting.ProductThumbPictureSize, true);
}
//there are many more entities are mapping here...
objList.Add(obj);
}
这适用于顺序foreach循环,但在使用并行化的foreach循环时会出错。
这是Stack Trace。
System.AggregateException: One or more errors occurred. ---> System.Data.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting. at System.Data.ProviderBase.DbConnectionClosedConnecting.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) at System.Data.SqlClient.SqlConnection.Open() at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen,
DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) --- End of inner exception stack trace --- at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) at System.Data.EntityClient.EntityConnection.Open() at System.Data.Objects.ObjectContext.EnsureConnection() at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at
Nop.Services.Media.PictureService.GetPicturesByProductId(Int32 productId, Int32 recordsToReturn) in c:\Users\Libraries\Nop.Services\Media\PictureService.cs:line 612 at Custom.Plugin.Core.CoreService.<>c__DisplayClass16.<CustomProducts>b__13(Product m, ParallelLoopState state) at System.Threading.Tasks.Parallel.<>c__DisplayClass2d`2.<ForEachWorker>b__24(Int32 i, ParallelLoopState state) at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c() at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) at System.Threading.Tasks.Task.<>c__DisplayClass10.<ExecuteSelfReplicating>b__f(Object param0) --- End of inner exception stack trace --- at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions) at System.Threading.Tasks.Task.Wait(Int32 millisecondsTimeout, CancellationToken cancellationToken) at System.Threading.Tasks.Task.Wait() at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Func`4 bodyWithLocal, Func`1 localInit, Action`1 localFinally) at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IList`1 list, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally)
at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable`1 source, ParallelOptions parallelOptions, Action`1 body, Action`2 bodyWithState, Action`3 bodyWithStateAndIndex, Func`4 bodyWithStateAndLocal, Func`5 bodyWithEverything, Func`1 localInit, Action`1 localFinally) at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable`1 source, Action`2 body) at Custom.Plugin.Core.CoreService.CustomProducts(Int32 TotalIds, Int32 langId) at Custom.Plugin.Core.CoreService.IncrementalDataImport() ---> (Inner Exception #0) System.Data.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting. at System.Data.ProviderBase.DbConnectionClosedConnecting.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry,
DbConnectionOptions userOptions) at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry) at System.Data.SqlClient.SqlConnection.Open() at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) --- End of inner exception stack trace --- at System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(Boolean openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection, String exceptionCode, String attemptedOperation, Boolean& closeStoreConnectionOnFailure) at System.Data.EntityClient.EntityConnection.Open() at System.Data.Objects.ObjectContext.EnsureConnection() at System.Data.Objects.ObjectQuery`1.GetResults(Nullable`1 forMergeOption) at System.Data.Objects.ObjectQuery`1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Data.Entity.Internal.Linq.InternalQuery`1.GetEnumerator() at System.Data.Entity.Infrastructure.DbQuery`1.System.Collections.Generic.IEnumerable<TResult>.GetEnumerator() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at
System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at Nop.Services.Media.PictureService.GetPicturesByProductId(Int32 productId, Int32 recordsToReturn) in c:\Users\Libraries\Nop.Services\Media\PictureService.cs:line 612 at Custom.Plugin.Core.CoreService.<>c__DisplayClass16.<CustomProducts>b__13(Product m, ParallelLoopState state) at System.Threading.Tasks.Parallel.<>c__DisplayClass2d`2.<ForEachWorker>b__24(Int32 i, ParallelLoopState state) at System.Threading.Tasks.Parallel.<>c__DisplayClassf`1.<ForWorker>b__c() at System.Threading.Tasks.Task.InnerInvoke() at System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) at System.Threading.Tasks.Task.<>c__DisplayClass10.<ExecuteSelfReplicating>b__f(Object param0)<--
可能是什么原因?为什么会出现这个错误?
答案 0 :(得分:1)
在这里,您尝试通过EF调度多个线程池线程来访问资源(数据库)。即你的并行循环向你带下划线的实体对象发送多个请求(调度多个线程)。遗憾的是,实体连接不是线程安全的,并且已记录在案here。