Linq In Parallel.ForEach

时间:2012-08-02 15:32:19

标签: linq c#-4.0 parallel.foreach

我有一个带有Linq查询的foreach循环。

一切都运行良好,直到我将foreach更改为Parallel.ForEach:

// get the task info   ---------
                Log("Populate task, guf code lists ...........................");
                List<SF_CO_ITEM> tasks = (from coi in ctx.SF_CO_ITEM
                                                    where coi.CO == co.ID
                                                    select coi).ToList();

               // foreach (SF_CO_ITEM t in tasks)
               // {
                Parallel.ForEach(tasks, t =>
                {
                    Log("Executing on t: " + t.ID);

                    // exception on next line:
                    List<SF_CO_LINE_ITEM> gufs = (from coli in ctx.SF_CO_LINE_ITEM      
                                                            where coli.CO_ITEM == t.ID
                                                            select coli).ToList();

我得到的例外是:

  

System.AccessViolationException未处理Message = Attempted to   读或写受保护的内存。这通常表明其他   记忆已腐败。 Source = Oracle.DataAccess StackTrace:          在Oracle.DataAccess.Client.OpsCon.Open(IntPtr&amp; opsConCtx,IntPtr&amp; opsErrCtx,OpoConValCtx * pOpoConValCtx,OpoConRefCtx&amp;   pOpoConRefCtx)          在Oracle.DataAccess.Client.ConnectionDispenser.Open(OpoConCtx opoConCtx)          在Oracle.DataAccess.Client.OracleConnection.Open()          在System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf(布尔值   openCondition,DbConnection storeConnectionToOpen,DbConnection   originalConnection,String exceptionCode,String attemptsOperation,   布尔和放大器; closeStoreConnectionOnFailure)          在System.Data.EntityClient.EntityConnection.Open()          在System.Data.Objects.ObjectContext.EnsureConnection()          在System.Data.Objects.ObjectQuery 1.GetResults(Nullable 1 forMergeOption)          在System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List 1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 source)          在ChangeOrder.Program。&lt;&gt; c_ DisplayClass19.b _16(SF_CHANGE_ORDER_ITEM   t)在C:\ VS_apps \ PMConsole \ PMC中   Tools \ ChangeOrderExecution \ Program.cs:第220行          在System.Threading.Tasks.Parallel。&lt;&gt; c_ DisplayClass2d 2.<ForEachWorker>b__23(Int32 i) at System.Threading.Tasks.Parallel.<>c__DisplayClassf 1.b _c()          在System.Threading.Tasks.Task.InnerInvoke()          在System.Threading.Tasks.Task.InnerInvokeWithArg(任务childTask)          在System.Threading.Tasks.Task。&lt;&gt; c_ DisplayClass7.b _6(Object   )          在System.Threading.Tasks.Task.ExecuteSelfReplicating(任务根)          在System.Threading.Tasks.Task.Execute()          在System.Threading.Tasks.Task.ExecutionContextCallback(Object obj)          at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean   ignoreSyncCtx)          在System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task&amp; currentTaskSlot)          在System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)          在System.Threading.Tasks.ThreadPoolTask​​Scheduler.TryExecuteTaskInline(任务   task,Boolean taskWasPreviouslyQueued)          at System.Threading.Tasks.TaskScheduler.TryRunInline(Task task,Boolean taskWasPreviouslyQueued,Object threadStatics)          在System.Threading.Tasks.Task.InternalRunSynchronously(TaskScheduler   调度)          在System.Threading.Tasks.Task.RunSynchronously(TaskScheduler scheduler)          在System.Threading.Tasks.Parallel.ForWorker [TLocal](Int32 fromInclusive,Int32 toExclusive,ParallelOptions parallelOptions,   动作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,   行动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,   行动1 localFinally) at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable 1来源,   行动`1机构)          在C:\ VS_apps \ PMConsole \ PMC中的ChangeOrder.Program.PerformChangeOrder(SF_CHANGE_ORDER co,SF_CLIENT_PROJECT cp,SFEntitiesQA ctx)   Tools \ ChangeOrderExecution \ Program.cs:第216行          在C:\ VS_apps \ PMConsole \ PMC Tools \ ChangeOrderExecution \ Program.cs中的ChangeOrder.Program.Main(String [] args):行   1373          在System.AppDomain._nExecuteAssembly(RuntimeAssembly程序集,String [] args)          在System.AppDomain.ExecuteAssembly(String assemblyFile,Evidence assemblySecurity,String [] args)          在Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()          在System.Threading.ThreadHelper.ThreadStart_Context(对象状态)          at System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback callback,Object state,Boolean   ignoreSyncCtx)          在System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback回调,对象状态)          在System.Threading.ThreadHelper.ThreadStart()InnerException:

我不确定我需要锁定什么,因为我只是抓取信息(只是RO,对吧?)。

我考虑过添加“AsParallel”,但我的理解是PLINQ指令只会导致查询与自身并行运行。

我找不到在Parallel.ForEach循环中运行Linq查询的人的任何示例,所以我甚至不确定我正在做什么是允许的。

1 个答案:

答案 0 :(得分:2)

为什么不单独进行连接而不是单独获取每个连接?由于它看起来像是在访问数据库,因此您的LINQ提供程序应该只编写查询并获取您正在查找的行。试试这个:

List<SF_CO_LINE_ITEM> gufs;
var query = from coi in ctx.SF_CO_ITEM
            where coi.CO == co.ID
            join coli in ctx.SF_CO_LINE_ITEM      
                on coi.ID == coli.CO_ITEM
            select coli;
// Confirm what the query looks like by calling 'query.ToString()'
gufs = query.ToList();

我通常将查询与实际的枚举/实现分开,这样我就可以验证查询看起来像我想要的那样。如果这是SF_CO_ITEMSF_CO_LINE_ITEM之间的1:M关系,那么您应该通过将联接更改为:

来执行GroupJoin
join coli in ctx.SF_CO_LINE_ITEM      
    on coi.ID == coli.CO_ITEM into tcoli
from tc in tcoli
select tc

至于为什么要获得此异常,可能与尝试从其他线程访问上下文有关。根据{{​​3}}:

  

Hidden Loop Body Dependencies

     

错误的循环依赖性分析是软件的常见来源       缺陷。请注意,所有并行循环体都不包含隐藏       依赖。这是一个容易犯的错误。

     

尝试共享类的实例(例如Random或。)的情况       跨并行迭代的非线程安全的DbConnection是       一个微妙依赖的例子。

因此,您唯一的选择是保持顺序而不是并行或将原始查询更改为连接,以便您第一次获得正确的数据。

希望有所帮助!