gpt4 book ai didi

c# - Xamarin Android - Task.Run 与 Task.Factory.StartNew 和 Thread.CurrentPrincipal

转载 作者:太空宇宙 更新时间:2023-11-03 14:58:01 24 4
gpt4 key购买 nike

我有一个 Xamarin.Android 项目,TargetFramework = Android 版本:8.0 (Oreo)。

我注意到以下问题:

  1. Thread.CurrentPrincipal 设置为自定义主体(要格外小心以确保它是可序列化的!)
  2. 调用 await Task.Run() 来运行一些任务。
  3. Task 中,如果它在不同的线程上执行,则不会设置 Thread.CurrentPrincipal。
  4. 如果您使用 Task.Factory.StartNew() 而不是 Task.Run(),那么在后台线程上运行的任务确实正确设置了 Thread.CurrentPrincipal。

换句话说,Task.Factory.StartNew 似乎将 CurrentPrinciple 流向新线程,而 Task.Run 则不会

此外,如果您在 NET 4.7 上重复此测试,则 Thread.CurrentPrincipal 在这两种情况下都会正确流动,因此这种行为差异只会在 Mono/Xamarin.Android 上运行时出现。

这是一个测试用例:

    [Fact]
public async Task LoginService_WhenUserLogsIn_PrincipalFlowsToAsyncTask()
{

var mockIdentity = new MockIdentity(true);
var mockPrincipal = new MockPrincipal(mockIdentity);
Thread.CurrentPrincipal = mockPrincipal ;

await Task.Factory.StartNew(async () =>
{
var newThreadId = Thread.CurrentThread.ManagedThreadId; // on different thread.
Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);

await Task.Factory.StartNew(() =>
{
// still works even when nesting..
newThreadId = Thread.CurrentThread.ManagedThreadId;
Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);

}, TaskCreationOptions.LongRunning);

}, TaskCreationOptions.LongRunning);

await Task.Run(() =>
{
// Following works on NET4.7 and fails under Xamarin.Android.
var newThreadId = Thread.CurrentThread.ManagedThreadId;
Assert.True(Thread.CurrentPrincipal.Identity.IsAuthenticated);
Assert.Equal(mockPrincipal, Thread.CurrentPrincipal);

});

}

以下是在 Xamarin.Android 应用程序下调试时的一些屏幕截图,在不同点显示以下内容:

  1. Thread.CurrentPrinicpal
  2. Thread.CurrentThread.ManagedThreadId
  3. TaskScheduler.Default
  4. TaskScheduler.Current
  5. TaskScheduler.FromCurrentSynchronizationContext();

这是 StartNew() 之前的样子:

enter image description here

这是 StartNew() 内部的样子:

enter image description here

请注意,通过 StartNew() 调度的任务正在线程池线程上执行,并且 ShcnronisationContext TaskScheduler 为空,因为此时没有当前同步上下文。但是,还要注意线程的主体已正确设置为“Daz”身份。

这是等待 Task.Factory.StartNew() 之后和调用 Task.Run() 之前的样子:

enter image description here

请注意,我们又回到了主线程,就像调用 StartNew() 之前一样。

但是,SyncContext TaskScheduler 似乎已更改(它的 ID 现在为 3)。不确定这是否与此问题相关。

现在这是 Task.Run() 期间的样子:

enter image description here

注意:Thread.CurrentPrincipal.IdentityName 已丢失(即因为 Prinicpal 没有像使用 StartNew() 那样流向该线程。

我们仍然在后台线程中,就像我们使用 StartNew() 一样。这个线程上没有 SynchronisationContext,这是我们对后台线程的期望,并且在 StartNew() 中是相同的,所以没有区别。Default 和 Current 任务计划程序看起来相同(均为 ID = 1),因此也没有区别。

我能看到的唯一区别是,Principal 没有流向线程。

这是什么原因?这是一个错误吗?我认为在使用 Task.Run() 时,Thread.CurrentPrinicpal 应该始终与 ExecutionContext 一起流动。

我还在 Github 上提出了一个问题:https://github.com/xamarin/xamarin-android/issues/1130

更新:看起来这已被确认为一个错误,希望它会被修复:https://github.com/mono/mono/pull/6326/files

最佳答案

编辑开始:

我将留下我的其余答案,尽管任何阅读此内容的人都应该注意到它与问题无关,我不介意将其悬而未决,但请不要将其标记下来。它下面有通信可能是相关的。

我仔细研究了这个问题并意识到了问题所在,并且可以诚实地同意我认为这可能是一个错误。我无法解释它,并且觉得知道前进是件好事。我将自己关注这个问题以寻求解决方案。

编辑结束:

我不完全确定我明白你在做什么。也许使用断点并将鼠标悬停在变量上?将这些变量放在两个任务之外,然后在它们运行后查看它们。

但这就是我认为您正在寻找的答案。输入 Foo 时,它只是一个具有 Task 返回类型的异步方法。是的,这意味着我们可以在调用时等待它,但在它实际在新线程上运行之前什么都不等待。因此,在 Foo 到达 await Task.Factory.StartNew 之前,您将保留在调用 await Foo() 的任何上下文中。

调用 Task.Factory.StartNew 从线程池中获取一个线程并在该线程上执行传递的操作。完成后,它计划在调用它的同一上下文中返回到 Foo。现在上下文再次等待 await Task.Run,它与 await Task.Factory.StartNew 做同样的事情。您将从线程池中获取一个线程,并在那里运行工作等。

这两个调用只有一个区别,那就是传递给 TaskFactory 的 TaskCreationOptions.LongRunning 参数...老实说,工厂所做的事情在所有环境中并不具体或相同,但它是在那里让工厂知道您的线程将存活更长的时间。我相信在 Windows 中它会从不同的线程池中提取线程,这意味着运行时间更长,但我不完全确定。无论哪种方式;对于每个调用,您仍在一个新线程上,而不是同一个线程,并且您在两者之间回到同一个线程。

此外,您可以在 await 调用结束时使用 .ConfigureAwait(false); 但这不会返回调用上下文。它将安排线程在当时最佳的情况下继续运行,如果您不知道,这可能会导致问题。它总体上更有效,但要确保您的方法的其余部分不需要在相同的上下文中进行操作。

希望这对您有所帮助。

关于c# - Xamarin Android - Task.Run 与 Task.Factory.StartNew 和 Thread.CurrentPrincipal,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47926132/

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