我如何在 Swift Playgrounds 中睡觉并获取最新的异步值? [英] How do I sleep in Swift Playgrounds and get the latest async values?

查看:103
本文介绍了我如何在 Swift Playgrounds 中睡觉并获取最新的异步值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 Swift Playgrounds 中测试/显示与延迟后改变值的函数相关的行为.为简单起见,我们只说它改变了一个字符串.我知道我可以通过 DispatchQueue.main.asyncAfter 延迟更新值的执行,并且我可以使用 usleepsleep 使当前线程休眠.

I'd like to test/display behavior in Swift Playgrounds related to a function that mutates values after a delay. For simplicity, let's just say it mutates a string. I know I can delay the execution of updating the value via DispatchQueue.main.asyncAfter and that I can sleep the current thread using usleep or sleep.

但是,由于 Playground 似乎在同步线程中运行,所以我无法在睡眠后看到变化.

However, since the playground is seemingly running in a synchronous thread, I'm not able to see the changes after sleeping.

这是我想做的一个例子:

Here's an example of what I would like to do:

var string = "original"

let delayS: TimeInterval = 0.100
let delayUS: useconds_t = useconds_t(delayS * 1_000_000)

func delayedUpdate(_ value: String) {
  DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayS) {
    string = value
  }
}

delayedUpdate("test2")
assert(string == "original")
usleep(delayUS)
print(string) // ❌ Prints "original"
assert(string == "test2") // ❌ Assertion failure. string is "original" here

delayedUpdate("test3")
assert(string == "test2") // ❌ Assertion failure. string is "original" here
usleep(delayUS)
print(string) // ❌ Prints "original"
assert(string == "test3") // ❌ Assertion failure. string is "original" here

delayedUpdate("test4")
assert(string == "test3") // ❌ Assertion failure. string is "original" here
usleep(delayUS)
print(string) // ❌ Prints "original"
assert(string == "test4") // ❌ Assertion failure. string is "original" here


请注意所有失败的断言,因为顶层的任何内容都看不到 string 的更改.这似乎是一个同步与异步线程的问题.


Notice all the failed assertions since anything at the top level doesn't see the changes to string. This seems like a synchronous vs. asynchronous thread issue.

我知道我可以通过用更多的 asyncAfter 替换 usleep 来修复它:

I know I can fix it by replacing usleep with more asyncAfter:

delayedUpdate("test2")
assert(string == "original")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayS) {
  print(string)
  assert(string == "test2")

  delayedUpdate("test3")
  assert(string == "test2")
  DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayS) {
    print(string)
    assert(string == "test3")

    delayedUpdate("test4")
    assert(string == "test3")
    DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delayS) {
      print(string)
      assert(string == "test4")
    }
  }
}

然而,每次应用延迟时,这都会导致缩进代码的灾难金字塔.这 3 个级别还不错,但是如果我有一个大操场,这将变得非常难以遵循.

However, this leads to a pyramid of doom of indented code each time the app is delayed. This is not too bad with 3 levels, but if I have a large playground, this will become really hard to follow.

有没有办法使用更接近第一个线性编程风格的东西,尊重延迟后更新的更新?

Is there a way to use something closer to the first linear programming style that respects updates updated after delays?

另一个可能的解决方案是将每个对 string 的引用包装在一个 asyncAfter 中:

Another potential solution is to wrap each reference to string in a asyncAfter:

delayedUpdate("test2")
assert(string == "original")
usleep(delayUS)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { print(string) }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { assert(string == "test2") }

delayedUpdate("test3")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { assert(string == "test2") }
usleep(delayUS)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { print(string) }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { assert(string == "test3") }

delayedUpdate("test4")
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { assert(string == "test3") }
usleep(delayUS)
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { print(string) }
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.001) { assert(string == "test4") }

然而,这也不是首选,因为它也很混乱,并且如果一次执行依赖于 string 的先前值来执行其功能,则可能容易出错.它还需要 0.001 或类似的修正以确保没有竞争条件.

However this is not preferred either since it is pretty messy as well, and probably error prone if one execution relies on the previous value of string to do its function, for example. It also needs a 0.001 or similar correction to ensure there is no race condition.

我如何在 Swift 游乐场中使用线性编程风格(例如使用 sleep),但让 sleep 之后的行正确反映在睡眠期间更新的值代码>?

How do I use a linear programming style (e.g. with sleep) in a Swift playground, but have values that are updated during the sleep be reflected correctly by the lines after sleep?

推荐答案

您正在创建竞争条件.忘记操场;只需考虑以下代码:

You're creating a race condition. Forget the playground; just consider the following code:

    print("start")
    DispatchQueue.main.asyncAfter(deadline:.now() + 1) {
        print("delayed")
    }
    sleep(2)
    print("done")

我们延迟 1 秒并打印delayed",我们休眠 2 秒并打印done".你认为哪个会先出现,延迟"?或完成"?如果您认为延迟"会先出现,你不明白 sleep 是做什么的.它阻塞了主线程.延迟直到阻塞消失后才能重新进入主线程.

We delay for 1 second and print "delayed", and we sleep for 2 seconds and print "done". Which do you think will appear first, "delayed" or "done"? If you think "delayed" will appear first, you don't understand what sleep does. It blocks the main thread. The delay cannot re-enter the main thread until after the blockage is gone.

这篇关于我如何在 Swift Playgrounds 中睡觉并获取最新的异步值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆