ここに2つの質問があります。1つ目は、 PLINQThread.CurrentPrincipal
のスレッドに伝播されるかどうかです。
ExecutionContext
これはの一部であり、ExecutionContextは呼び出し元のスレッドからキャプチャされ、新しいスレッド/タスク/スレッドプールスレッドが開始されるときに新しい/リサイクルされたスレッドにコピーされるため、答えは「はい」です。
次のテストケース(.NET 4.0で実行)はこれを示しています。
[TestMethod]
public void TestMethod1()
{
// Capture the current logged in account.
// Could be a GenericPrincipal as well with some random value
// set on the identity name.
IPrincipal p = new WindowsPrincipal(WindowsIdentity.GetCurrent());
// Set the current principal.
Thread.CurrentPrincipal = p;
// Set the synchronization context.
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext());
// Context is not null.
Assert.IsNotNull(SynchronizationContext.Current);
// PLINQ.
var plinqThreadDetails =
// Go parallel. This number needs to be reasonably
// high to force parallelization as PLINQ might
// use this thread if the size is small.
from i in Enumerable.Range(0, 4000).AsParallel().
// Force parallelization. At best, this is
// a suggestion.
WithExecutionMode(ParallelExecutionMode.ForceParallelism)
select new {
// These values are retreived on another thread.
IdentityName = Thread.CurrentPrincipal.Identity.Name,
Thread.CurrentThread.ManagedThreadId,
};
// Was there any parallelization?
bool anyParallel = false;
// Make assertions.
// The managed thread id is different than the current one.
foreach (var plinqThreadDetail in plinqThreadDetails)
{
// But the principal still flowed, even though on a different
// thread.
Assert.AreEqual(Thread.CurrentPrincipal.Identity.Name,
plinqThreadDetail.IdentityName);
// Update any parallel.
anyParallel |= (plinqThreadDetail.ManagedThreadId !=
Thread.CurrentThread.ManagedThreadId);
}
// There was *some* parallelization.
Assert.IsTrue(anyParallel);
}
PLINQで使用されているかどうかについてSynchronizationContext
は、使用されておらず、意味がありません。
SynchronizationContext
通常、特定のコンテキスト(通常はスレッドであり、UIアプリケーションを考えますが、ASP.NET同期コンテキストを考えると常にではありません)への呼び出しをシリアル化することを意味することを考えると、PLINQが並列化から得る利益はすべて無効になります。すべての呼び出しは、を介してマーシャリングする必要がありSynchronizationContext
ます。
PLINQの利点は、これらの操作を一度に1つずつではなく、同時に実行できることです。
SynchronizationContext
次のテストケース(前のテストケースとほぼ同じ)は、がPLINQスレッドでキャプチャされていないことを証明しています。
[TestMethod]
public void TestMethod2()
{
// Set the synchronization context.
SynchronizationContext.SetSynchronizationContext(
new SynchronizationContext());
// Context is not null.
Assert.IsNotNull(SynchronizationContext.Current);
// PLINQ.
var plinqThreadDetails =
// Go parallel. This number needs to be reasonably
// high to force parallelization as PLINQ might
// use this thread if the size is small.
from i in Enumerable.Range(0, 4000).AsParallel().
// Force parallelization.
WithExecutionMode(ParallelExecutionMode.ForceParallelism)
select new {
// These values are retreived on another thread.
SynchronizationContextIsNull =
SynchronizationContext.Current == null,
Thread.CurrentThread.ManagedThreadId,
};
// Make assertions.
// Was there any parallelization?
bool anyParallel = false;
// Make assertions.
// The synchronization context on the PLINQ thread was
// not set, only if on a different thread.
foreach (var plinqThreadDetail in plinqThreadDetails)
{
// If the thread id is different.
if (plinqThreadDetail.ManagedThreadId !=
Thread.CurrentThread.ManagedThreadId)
{
// The synchronization context was null.
Assert.IsTrue(plinqThreadDetail.SynchronizationContextIsNull);
// There was something on another thread.
anyParallel = true;
}
else
{
// The synchronization context is not null.
Assert.IsFalse(plinqThreadDetail.SynchronizationContextIsNull);
}
}
// There was *some* parallelization.
Assert.IsTrue(anyParallel);
}