2012-08-02 6 views
0

내부에 Linq 쿼리가있는 foreach 루프가 있습니다. 내가 Parallel.ForEach에 foreach 문을 변경할 때까지Linq In 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 읽거나 쓰기 에 시도되지 않은 메시지 =였다 보호 된 메모리. 이것은 종종 다른 메모리가 손상되었음을 나타냅니다. 소스 = Oracle.DataAccess 스택 트레이스 : Oracle.DataAccess.Client.OpsCon.Open (&을 IntPtr opsConCtx, &을 IntPtr opsErrCtx, OpoConValCtx * pOpoConValCtx, OpoConRefCtx & pOpoConRefCtx) Oracle.DataAccess.Client.ConnectionDispenser.Open에서 (OpoConCtx opoConCtx에서 ) System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf (부울 openCondition, DbConnection storeConnectionToOpen, DbConnection originalConnection 스트링으로 Exception 문자열 attemptedOperation, 부울 & closeStoreConnectionOnFailure) 에서 Oracle.DataAccess.Client.OracleConnection.Open()에서 에서 System.Data.EntityClient System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List 1..ctor에서 System.Data.Objects.ObjectQuery 1.GetResults(Nullable 1 forMergeOption) 에서 System.Data.Objects.ObjectContext.EnsureConnection()에서 .EntityConnection.Open() (IEnumerable을 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 소스) 에서 ChangeOrder.Program. < C에서> C_ DisplayClass19.b _16 (SF_CHANGE_ORDER_ITEM t) : \ VS_apps \ PMConsole \ PMC 도구 \ ChangeOrderExecution \ Program.cs : System.Threading.Tasks.Parallel에서 선 220 . <> C_ 는 System.Threading.Tasks.Task에서 System.Threading.Tasks.Task.InnerInvokeWithArg (작업 childTask) 에서 System.Threading.Tasks.Task.InnerInvoke()에서 2.<ForEachWorker>b__23(Int32 i) at System.Threading.Tasks.Parallel.<>c__DisplayClassf 1.B _c()를 DisplayClass2d . System.Threading.Tasks.Task에서 System.Threading.Tasks.Task.Execute() 에서 System.Threading.Tasks.Task.ExecuteSelfReplicating (작업 루트) 에서 <> C_ DisplayClass7.b _6 (객체 ) .ExecutionContextCallback하여 System.Threading에서 System.Threading.Tasks.Task.ExecuteWithThreadLocal (작업 & currentTaskSlot) 에서 (개체 OBJ) System.Threading.ExecutionContext.Run에서 (의 ExecutionContext의 ExecutionContext, ContextCallback 콜백, 객체 상태, 부울 ignoreSyncCtx) .Tasks.Task.ExecuteEntry (Boolean bPreventDoubleExecution) at System.Threading.Tasks.ThreadPoolTaskScheduler.TryExecuteTaskInline (작업) 6,작업, 부울 taskWasPreviouslyQueued) System.Threading.Tasks.TaskScheduler.TryRunInline (작업 작업, 부울 taskWasPreviouslyQueued, threadStatics 객체) System.Threading.Tasks.Task.InternalRunSynchronously에서 (TaskScheduler 스케줄러) 에서 System.Threading.Tasks에서 .Task.RunSynchronously (TaskScheduler scheduler) at System.Threading.Tasks.Parallel.ForWorker [TLocal (INT32 fromInclusive, INT32 toExclusive, ParallelOptions의 parallelOptions, 액션 1 body, Action 2 bodyWithState, Func을 4 bodyWithLocal, Func 1 localInit, 액션 목록 ParallelOptions의 parallelOptions, 액션 bodyWithState, 액션 3 bodyWithStateAndIndex, Func 4 bodyWithStateAndLocal, Func을 5 bodyWithEverything, Func 1 localInit, 액션 소스 parallelOptions의 parallelOptions, 액션 bodyWithState, 액션 3 bodyWithStateAndIndex, Func 4 bodyWithStateAndLocal, Func을 5 bodyWithEverything, Func 1 localInit,,691 363,210 액션 1 localFinally) at System.Threading.Tasks.Parallel.ForEach[TSource](IEnumerable C에서 ChangeOrder.Program.PerformChangeOrder (SF_CHANGE_ORDER 공동 SF_CLIENT_PROJECT의 CP, SFEntitiesQA CTX)에서 1 개 소스 Action`1 체) : \ VS_apps \ PMConsole \ PMC 도구 \ ChangeOrderExecution \ Program.cs : 라인 216 C : \ VS_apps \ PMConsole \ PMC Tools \ ChangeOrderExecution \ Program.cs의 ChangeOrder.Program.Main (String [] args)에서 at System.AppDomain._nExecuteAssembly (RuntimeAssembly assembly, String [] args) at System.Threading.ThreadHelper.ThreadStart_Context (Object state)에서 을 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 에서 가져 오려면 어셈블리 파일의 System.AppDomain.ExecuteAssembly (String assemblyFile, Evidence assemblySecurity, String [] args) 91,363,210 System.Threading.ExecutionContext.Run에서 (ExecutionContext에의 ExecutionContext는 ContextCallback 콜백, 객체 상태 부울 ignoreSyncCtx) System.Threading.ExecutionContext.Run에서 System.Threading.ThreadHelper에서 을 (ExecutionContext에 ExecutionContext에, ContextCallback 콜백 상태 객체). ThreadStart() InnerException :

나는 단지 정보를 얻고 있기 때문에 잠글 필요가 있을지 모르겠다.

"AsParallel"을 추가하는 것에 대해 생각해 보았습니다.하지만 필자는 PLINQ 지시문을 사용하여 쿼리가 자체적으로 병렬로 실행되도록합니다.

Parallel.ForEach 루프 내에서 Linq 쿼리를 실행하는 사용자의 사례를 찾을 수 없으므로 내가하는 일이 허용되는지조차 알지 못합니다.

+1

'foreach'를'Parallel.ForEach'로 바꾸는 것은 큰 변화입니다. 작업이 실제로 병렬로 실행될 수 있는지 확인해야합니다. –

답변

2

왜 각자 개별적으로 가입하는 대신 가입 자체를하는 것이 좋을까요? 이것이 DB를 치는 것처럼 보이기 때문에 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(); 

난 보통, 실제 열거/물질화에서 내가 원하는처럼 쿼리가 보이는 것을 확인할 수 있습니다 그런 식으로 쿼리를 분리 할 수 ​​있습니다. 이 1 인 경우 : SF_CO_ITEMSF_CO_LINE_ITEM 간의 M 관계, 당신은이에 가입 변경하여 GroupJoin을 수행해야합니다

이 예외를 얻고있는 이유에 관해서는,하려고 함께 할 수있는 뭔가가있을
join coli in ctx.SF_CO_LINE_ITEM  
    on coi.ID == coli.CO_ITEM into tcoli 
from tc in tcoli 
select tc 

다른 thread로부터 컨텍스트에 액세스합니다. 루프 종속성

숨겨진 루프 본체 종속

잘못된 분석 소프트웨어 결함의 빈번한 소스이다 MSDN article on Parallel loops 따라.모든 병렬 루프 본문에 숨겨진 종속성이 포함되지 않도록주의하십시오. 이것은 실수하기 쉬운 것입니다.

무작위 또는 DbConnection과 같은 클래스의 인스턴스를 공유하는 경우 스레드로부터 안전하지 않은 병렬 반복을 통해 미묘한 종속성의 예입니다.

그래서 유일한 옵션은 평행 대신 계속 유지하거나 원래 쿼리를 조인으로 변경하여 처음으로 올바른 데이터를 얻을 수 있도록하는 것입니다.

희망 하시겠습니까?

+0

감사합니다. * * * 2 개의 쿼리를 결합 할 수는 있지만, 하나의 객체 만 필요로하는 foreach 블록에는 많은 쿼리가 있지만 다른 하나는 필요하지 않습니다. 모든 거래가 1 건의 거래에서 발생하기 때문에 컨텍스트를 실제로 구분할 수는 없습니다. 그래서 내가 가지고있는 유일한 실현 가능한 선택은 그것을 계속 유지하는 것입니다. – micahhoover

+0

스레드 안전 데이터베이스 컨텍스트 클래스가 있다면 좋을 것입니다. 아마 거기에 돈을 벌 수있을 것입니다. – micahhoover