0

我有一个 foreach 循环,里面有 Linq 查询。

在我将 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=尝试读取或写入受保护的内存。这通常表明其他内存已损坏。Source=Oracle.DataAccess StackTrace:在 Oracle.DataAccess.Client.ConnectionDispenser.Open(OpoConCtx opoConCtx) 的 Oracle.DataAccess.Client.ConnectionDispenser.Open(IntPtr& opsConCtx, IntPtr& opsErrCtx, OpoConValCtx* pOpoConValCtx, OpoConRefCtx& pOpoConRefCtx) 处。 System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf 处的 Client.OracleConnection.Open()(布尔 openCondition,DbConnection storeConnectionToOpen,DbConnection originalConnection,字符串异常代码,字符串尝试操作,布尔和 closeStoreConnectionOnFailure)在 System.Data.EntityClient.EntityConnection.Open() 处。数据。1.GetResults(Nullable1 forMergeOption) 在 System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 ChangeOrder.Program.<>c_ DisplayClass19.b _16(SF_CHANGE_ORDER_ITEM t) 在 C:\VS_apps\PMConsole\PMC Tools\ChangeOrderExecution\Program .cs:System.Threading.Tasks.Parallel.<>c_DisplayClass2d 处的 220 行1.b 2.<ForEachWorker>b__23(Int32 i) at System.Threading.Tasks.Parallel.<>c__DisplayClassf_c () 处 System.Threading.Tasks.Task.InnerInvoke() 处 System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask)在 System.Threading.Tasks.Task.<> c_DisplayClass7.b_6(Object ) 在 System.Threading.Tasks.Task.ExecuteSelfReplicating(Task root) 在 System.Threading.Tasks.Task.Execute() 在 System.Threading.Tasks.Task.ExecutionContextCallback(Object obj) 在 System.Threading.ExecutionContext .Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) 在 System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) 在 System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) 在 System.Threading.Tasks。 System.Threading.Tasks.TaskScheduler.TryRunInline(Task task, Boolean taskWasPrevouslyQueued, Object threadStatics) 在 System.Threading.Tasks.Task 的 ThreadPoolTask​​Scheduler.TryExecuteTaskInline(Task task, Boolean taskWasPreviousQueued)。InternalRunSynchronously(TaskScheduler scheduler) at System.Threading.Tasks.Task.RunSynchronously(TaskScheduler scheduler) at System.Threading.Tasks.Parallel.ForWorker[TLocal](Int32 fromInclusive, Int32 toExclusive, ParallelOptions parallelOptions, Action1 body, Action2 bodyWithState,Func 4 bodyWithLocal, Func1 localInit,Action 1 localFinally) at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IList1 列表,ParallelOptions parallelOptions,Action 1 body, Action2 bodyWithState,Action 3 bodyWithStateAndIndex, Func4 bodyWithStateAndLocal,Func 5 bodyWithEverything, Func1 localInit,Action 1 localFinally) at System.Threading.Tasks.Parallel.ForEachWorker[TSource,TLocal](IEnumerable1 source,ParallelOptions,Action 1 body, Action2 bodyWithState,Action 3 bodyWithStateAndIndex, Func4 bodyWithStateAndLocal,Func 5 bodyWithEverything, Func1 localInit,Action1 localFinally) at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable1 来源,Action`1 body) 在 ChangeOrder.Program.PerformChangeOrder(SF_CHANGE_ORDER co, SF_CLIENT_PROJECT cp, SFEntitiesQA ctx) 在 C:\VS_apps\PMConsole\PMC Tools\ChangeOrderExecution\Program.cs:line 216 at ChangeOrder.Program.Main( C:\VS_apps\PMConsole\PMC Tools\ChangeOrderExecution\Program.cs 中的 String[] args):System.AppDomain._nExecuteAssembly 的第 1373 行(RuntimeAssembly 程序集,String[] args)在 System.AppDomain.ExecuteAssembly(字符串 assemblyFile,Evidence assemblySecurity, String[] args) 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state,Boolean ignoreSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 在 System.Threading.ThreadHelper.ThreadStart() InnerException:

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

我考虑过添加“AsParallel”,但我的理解是这是一个 PLINQ 指令,它只会导致查询相对于自身并行运行。

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

4

1 回答 1

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_ITEM如果这是和之间的 1:M 关系SF_CO_LINE_ITEM,那么您应该通过将联接更改为来执行 GroupJoin:

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

至于为什么会出现此异常,可能与尝试从不同的线程访问上下文有关。根据关于并行循环的 MSDN 文章

隐藏循环体依赖

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

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

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

希望有帮助!

于 2012-08-02T16:09:06.990 回答