比如说,我有以下代码:
IPrincipal capturedPrincipal = Thread.CurrentPrincipal;
myseq.AsParallel().Select(x =>
{
Thread.CurrenctPrincipal = capturedPrincipal;
/*call code protected with CAS*/
});可以肯定的是,Thread.CurrenctPrincipal将传播到执行Select委托的每一个线程。我已经意识到,如果设置了适当的SynchronizationContext,这种情况就会自动发生。那么,PLINQ在ThreadPool上排队工作项目时会使用SynchronizationContext吗?如果没有,为什么?
附注:
我认为重要的是要注意,上面的代码是在IIS/WAS下托管的WCF环境中执行的(没有ASP.NET兼容性)。
编辑:发现类似的问题证实了我看到的同样的行为。
Edit2:修改了casperOne的测试,但是失败了,说三次是一样的
[Test]
public void Test1()
{
var principal = new GenericPrincipal(new GenericIdentity("test"), new string[0]);
Thread.CurrentPrincipal = principal;
int threadID = Thread.CurrentThread.ManagedThreadId;
Enumerable.Range(0, 4000).AsParallel()
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
.Select(x =>
{
Assert.AreSame(Thread.CurrentPrincipal, principal);
Assert.AreNotEqual(Thread.CurrentThread.ManagedThreadId, threadID);
return x;
})
.ToArray();
}发布于 2012-10-24 12:32:26
这里有两个问题。第一个问题是Thread.CurrentPrincipal是否传播到PLINQ中的线程。
答案是肯定的,因为这是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);
}关于SynchronizationContext是否在PLINQ中使用的问题,它没有,也没有任何意义。
考虑到使用SynchronizationContext通常意味着将调用序列化到特定的上下文(通常是线程,请考虑UI应用程序,但并不总是这样,给定ASP.NET同步上下文),您将扼杀PLINQ从并行化中获得的任何收益,因为每个调用都必须通过SynchronizationContext封送回封。
PLINQ的好处在于能够同时执行这些操作,而不是一次一次。
下面的测试用例(非常类似于前一个测试用例)证明了PLINQ线程没有捕获SynchronizationContext:
[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);
}https://stackoverflow.com/questions/13048673
复制相似问题