0

内部に 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=保護されたメモリを読み書きしようとしました。これは多くの場合、他のメモリが破損していることを示しています。Source=Oracle.DataAccess StackTrace: at Oracle.DataAccess.Client.OpsCon.Open(IntPtr& opsConCtx, IntPtr& opsErrCtx, OpoConValCtx* pOpoConValCtx, OpoConRefCtx& pOpoConRefCtx) at Oracle.DataAccess.Client.ConnectionDispenser.Open(OpoConCtx opoConCtx) at Oracle.DataAccess. Client.OracleConnection.Open() で System.Data.EntityClient.EntityConnection.OpenStoreConnectionIf (ブール値の openCondition、DbConnection storeConnectionToOpen、DbConnection originalConnection、String exceptionCode、String attemptsOperation、Boolean& closeStoreConnectionOnFailure) で System.Data.EntityClient.EntityConnection.Open() で 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 source) 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 行2.<ForEachWorker>b__23(Int32 i) at System.Threading.Tasks.Parallel.<>c__DisplayClassfSystem.Threading.Tasks.Task.InnerInvoke() の System.Threading.Tasks.Task.InnerInvokeWithArg(Task childTask) の 1.b _c( ) System.Threading.Tasks.Task.<>c_ DisplayClass7.bでSystem.Threading.Tasks.Task.ExecuteSelfReplicating(タスク ルート) の _6(オブジェクト) System.Threading.Tasks.Task.Task.ExecutionContextCallback(オブジェクト obj) の System.Threading.ExecutionContext .Run(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態、Boolean ignoreSyncCtx) System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot) at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution) at System.Threading.Tasks. ThreadPoolTask​​Scheduler.TryExecuteTaskInline (タスク タスク、ブール値の taskWasPreviouslyQueued) の System.Threading.Tasks.TaskScheduler.TryRunInline (タスク タスク、ブール値の taskWasPreviouslyQueued、オブジェクト threadStatics) の System.Threading.Tasks.Task.System.Threading.Tasks.Task.RunSynchronously(TaskScheduler スケジューラ) の InternalRunSynchronously(TaskScheduler スケジューラ) 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 list、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 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](IEnumerableC:\VS_apps\PMConsole\PMC Tools\ChangeOrderExecution\Program.cs:line 216 の ChangeOrder.Program.Main( String[] args) in C:\VS_apps\PMConsole\PMC Tools\ChangeOrderExecution\Program.cs: System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence) の行 1373 assemblySecurity, String[] args) で Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() で System.Threading.ThreadHelper.ThreadStart_Context(オブジェクト状態) で System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback コールバック, オブジェクト状態,System.Threading.ThreadHelper.ThreadStart() で System.Threading.ExecutionContext.Run(ExecutionContext executionContext、ContextCallback コールバック、オブジェクト状態) で Boolean ignoreSyncCtx) InnerException:

情報を取得しているだけなので、何をロックする必要があるのか​​ わかりません(ROだけですよね?)。

「AsParallel」を追加することを考えましたが、それはクエリをそれ自体に対して並列に実行させるだけの PLINQ ディレクティブであると理解しています。

Parallel.ForEach ループ内で Linq クエリを実行している例を見つけることができないため、自分が何をしているのかさえわかりません。

4

1 に答える 1

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:Mの関係である場合はSF_CO_ITEMSF_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 に答える