gpt4 book ai didi

.net - PLINQ 是否尊重 SynchronizationContext?

转载 作者:行者123 更新时间:2023-12-03 13:20:54 28 4
gpt4 key购买 nike

说,我有以下代码:

IPrincipal capturedPrincipal = Thread.CurrentPrincipal;
myseq.AsParallel().Select(x =>
{
Thread.CurrenctPrincipal = capturedPrincipal;
/*call code protected with CAS*/
});

确定 Thread.CurrenctPrincipal 将传播到 Select 所在的每个线程的委托(delegate)将被执行。我已经意识到,如果我有正确的 SynchronizationContext 设置这将自动发生。 PLINQ 也使用 SynchronizationContextThreadPool 上排队工作项目时?如果没有,为什么?

p.s.

我认为需要注意的是,上面的代码是在 IIS/WAS 下托管的 WCF 环境中执行的(不兼容 ASP.NET)。

编辑:
找到 a similar question确认我目睹的相同行为。

编辑2:
修改了 casperOne 的测试,它说 threadid 是一样的失败:
    [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();
}

最佳答案

这里有两个问题。首先是是否 Thread.CurrentPrincipal 传播到 PLINQ 中的线程.

答案是肯定的,因为这是 ExecutionContext 的一部分。和 ExecutionContext is captured from the calling thread and copied to the new/recycled thread when a new thread/task/thread pool thread is started .

以下测试用例(在 .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 synchronization context ),你会扼杀 PLINQ 从并行化中获得的任何 yield ,因为每次调用都必须是通过 SynchronizationContext 编码(marshal)回来.

PLINQ 的好处在于能够同时执行这些操作,而不是一次一个。

下面的测试用例(与前一个非常相似)证明 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);
}

关于.net - PLINQ 是否尊重 SynchronizationContext?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13048673/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com