- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我有一个 Xamarin.Android 项目,TargetFramework = Android 版本:8.0 (Oreo)。
我注意到以下问题:
Thread.CurrentPrincipal
设置为自定义主体(要格外小心以确保它是可序列化的!)await Task.Run()
来运行一些任务。Task
中,如果它在不同的线程上执行,则不会设置 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 应用程序下调试时的一些屏幕截图,在不同点显示以下内容:
这是 StartNew() 之前的样子:
这是 StartNew()
内部的样子:
请注意,通过 StartNew() 调度的任务正在线程池线程上执行,并且 ShcnronisationContext TaskScheduler 为空,因为此时没有当前同步上下文。但是,还要注意线程的主体已正确设置为“Daz”身份。
这是等待 Task.Factory.StartNew() 之后和调用 Task.Run() 之前的样子:
请注意,我们又回到了主线程,就像调用 StartNew() 之前一样。
但是,SyncContext TaskScheduler 似乎已更改(它的 ID 现在为 3)。不确定这是否与此问题相关。
现在这是 Task.Run() 期间的样子:
注意: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/
完成此任务的最佳方法是什么:主线程(线程 A)创建另外两个线程(线程 B 和线程 C)。线程 B 和 C 执行繁重的磁盘 I/O,最终需要将它们创建的资源传递给线程 A,然后调用外部 DLL 文件中的
我是一名对 Julia 语言感兴趣的新手程序员。文档( https://docs.julialang.org/en/v1/base/multi-threading/ )说 Threads.@threa
python中的thread.start_new_thread和threading.Thread.start有什么区别? 我注意到,当调用 start_new_thread 时,新线程会在调用线程终止
我正在学习安卓蓝牙编程。我从 Google 的 Android 开发者网站上复制了大部分代码以供学习。这个想法是监听服务器上的连接是在一个新线程中完成的,而不会阻塞 UI 线程。当收到连接请求时,连接
执行对象方法的线程是否依赖于创建它的线程上的线程? 假设您的 java 应用程序中有两个线程 Thread1 和 Thread2,以及两个类 ClassA 和 ClassB。 您在 Thread1 上
我正在用这段代码测试 C++11 线程,但是在创建线程时,我遇到了错误没有匹配函数调用 'std::thread::thread()'. 这就像我给 std::thread ctr 的函数有什么问题,
我有如下类 eventEngine 和网关: class eventEngine { public: eventEngine(); std::thread threa; std
我需要运行与列表 dirlist 中的元素一样多的 Observer 类线程。当我运行它 python 控制台时,它可以正常工作。 class Observer(Thread): def ru
我在一本 Java 书中读到了下面的代码。我知道主类默认继承 Thread 类,所以 currentThread();而不是 Thread.currentThread();也会做这项工作。 但我不明白
我在我的系统中使用第 3 方 API,该 API 启动一个永久运行的用户线程。一旦我的程序结束,JVM 由于该线程而继续运行,因此我尝试获取此线程引用并通过更改它 thread.setDaemon(t
我所知道的 Python 中的每个对象都可以通过调用来处理其基类初始化: super(BaseClass, self).__init__() threading.Thread 的子类似乎不是这种情况,
在我最近从事的 Xamarin 项目中,我可以看到开发人员使用了 Java.Lang.Thread 以及 System.Threading.Thread(用于非常相似的操作 - 例如在后台加载数据)。
我在 Julia 中运行双循环。代码非常简单。 w = rand(1000,1000) function regular_demo(w::Array{Float64, 2}) n = size
我在 Windows 上使用 Python 3。我正在使用 threading.Thread动态运行一个函数,我可以带参数或不带参数调用它。我正在设置一个列表,其中的第一项是定义路径的字符串。其他参数
我遇到了一些使用线程模块(使用 Python 2.6)管理线程的示例。 我想了解的是这个例子是如何调用“运行”方法的,在哪里调用的。我在任何地方都看不到它。 ThreadUrl 类在 main() 函
假设我从 threading.Thread 派生: from threading import Thread class Worker(Thread): def start(self):
关闭。这个问题需要debugging details .它目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and th
使用 WinDbg 和 SOS,我有以下内容: 0:011> !threads ThreadCount: 7 UnstartedThread: 0 BackgroundThread: 4 Pendin
App Engine 给出错误: com.google.apphosting.api.ApiProxy$CallNotFoundException: Can't make API call urlfe
我正在尝试将 Swing JEditorPane 嵌入到 JavaFX 项目中,如下代码所示。 Platform.runLater(() -> { SyntaxTester ob = new
我是一名优秀的程序员,十分优秀!