由于我的理解有限(甚至是错误),Async.StartImmediate和Async.RunSynchronously都会在当前线程上启动异步计算.那么这两个函数之间究竟有什么区别呢?谁能帮忙解释一下?
更新:
在https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs查看F#源代码后,我想我有点理解会发生什么.Async.StartImmediate在当前线程上启动异步.在遇到异步绑定后,它是否会继续在当前线程上运行取决于异步绑定本身.例如,如果异步绑定调用Async.SwitchToThreadPool,它将在ThreadPool而不是当前线程上运行.在这种情况下,如果要返回当前线程,则需要调用Async.SwitchToContext.否则,如果异步绑定没有切换到其他线程,Async.StartImmediate将继续在当前线程上执行异步绑定.在这种情况下,如果您只想保留当前线程,则无需调用Async.SwitchToContext.
Dax Fohl的示例在GUI线程上运行的原因是因为Async.Sleep仔细捕获SynchronizationContext.Current并确保使用SynchronizationContext.Post()在捕获的上下文中继续运行.见https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs#L1631,其中unprotectedPrimitiveWithResync包装改变"args.cont"(延续)是一个邮政所捕获的上下文(参见:https://github.com/fsharp/fsharp/blob/master/src/fsharp/FSharp.Core/control.fs#L1008 - trampolineHolder.Post基本上SynchronizationContext.Post).这仅在SynchronizationContext.Current不为null时才有效,GUI线程始终如此.特别是,如果您使用StartImmediate在控制台应用程序中运行,您会发现Async.Sleep确实会转到ThreadPool,因为控制台应用程序中的主线程没有SynchronizationContext.Current.
总而言之,这确实适用于GUI线程,因为Async.Sleep,Async.AwaitWaitHandle等某些功能会仔细捕获并确保回发到上一个上下文.它看起来是一种故意的行为,但是这似乎没有在MSDN中的任何地方记录.
请参阅以下代码.
let x = Seq.head [1.0; 2.0] // This is ok.
type Func<'T> = { f: seq<'T> -> 'T }
let func = { f = Seq.head }
// Compilation error: This expression was expected to have type seq<obj> but here has type 'a list
let y = func.f [1.0; 2.0]
let z = func.f ([1.0; 2.0] |> List.toSeq) // This is ok.
Run Code Online (Sandbox Code Playgroud)
我不明白为什么Seq.head和fund.f的行为在这里有所不同.它对我来说看起来像编译器错误.但是,如果这是设计的,有人可以帮我解释一下吗?非常感谢!
这是一个非常简单的例子来展示我尝试做的事情。红色圆圈可以拖动,松开后会回到原来的位置,如第一张图所示。当在拖动过程中拉起 iPad Dock 时会出现问题,然后.onEnded将永远不会调用DragGesture并且红色圆圈被卡住,如第二个图像所示。我不明白为什么.onEnded不叫。我在这里缺少什么?
我想到了通过offset在 SceneDelegate 中重置来解决的一种解决方法sceneDidBecomeActive,但是如果 iPad 底座只是被拉起但不会导致应用程序变为非活动状态,即进入后台模式,则它不起作用。在这种情况下,不会调用 SceneDelegate 中的任何函数,我发现无法检测到 DragGesture 已被中断。任何可能的解决方案?
struct ContentView: View {
@State private var offset = CGSize.zero
var body: some View {
ZStack {
Rectangle()
.fill(Color.clear)
.frame(width: 100, height: 100)
.border(Color.black, width: 5)
Circle()
.fill(Color.red)
.frame(width: 90, height: 90)
.offset(offset)
.gesture(
DragGesture()
.onChanged() { self.offset = $0.translation }
.onEnded() { _ in self.offset = CGSize.zero })
}
}
}
Run Code Online (Sandbox Code Playgroud)
我想在创建视图后动态更改视图的过渡。isTransition1我通过单击按钮在transition1和 之间切换来切换状态变量,transition2如下所示。但是,如果这些过渡之一是不透明的,则它不会按预期工作。更改过渡后立即删除的视图始终保持其原始过渡。令人惊讶的是,如果我改为transition2幻灯片,它会毫无问题地工作。要删除的视图将使用新的过渡。有什么办法可以让不透明度在这里发挥作用吗?
let transition1 = AnyTransition.asymmetric(insertion: .move(edge: .trailing),
removal: .move(edge: .leading))
let transition2 = AnyTransition.opacity
struct Wrapper1<Content: View>: View {
let content: Content
var body: some View {
content
}
}
struct Wrapper2<Content: View>: View {
let content: Content
var body: some View {
content
}
}
struct TextView: View {
let count: Int
let color: Color
var body: some View {
ZStack {
color
.edgesIgnoringSafeArea(.all)
.frame(maxWidth: UIScreen.main.bounds.width,
maxHeight: UIScreen.main.bounds.height) …Run Code Online (Sandbox Code Playgroud)