jjzjj

swift - DispatchGroup 通知 block 被提前调用

coder 2023-09-14 原文

在我的应用程序中早期调用 DispatchGroup 的通知 block 时出现问题,并制作了这个 playground 示例进行实验。根据输出,有时它甚至在第一个 .leave() 之前被调用。感觉我错过了一些明显的东西,现在我已经看了太久了。

let s = DispatchSemaphore(value: 1)
let dg = DispatchGroup()
func go() -> Void {
    for i in 1...2 {
        doWork(attemptNo: i, who: "Lily", secs: Double.random(in: 1.0...5.0))
        doWork(attemptNo: i, who: "Emmie", secs: Double.random(in: 1.0...10.0))
        doWork(attemptNo: i, who: "Wiley", secs: Double.random(in: 1.0...3.0))
    }
}
func doWork(attemptNo: Int, who: String, secs: TimeInterval) -> Void {
    DispatchQueue.global().async {
        dg.enter()
        print("\(who) wants to work, will wait \(secs) seconds, attempt #\(attemptNo)")
        if s.wait(timeout: .now() + secs) == .timedOut {
            print("\(who) was denied. No soup for me! Task #\(attemptNo) not going to happen.")
            dg.leave()
            return
        }
        let workSecs = UInt32(Int.random(in: 1...3))
        print("\(who) went to work for \(workSecs) seconds on task #\(attemptNo)")

        DispatchQueue.global().asyncAfter(deadline: .now() + TimeInterval(workSecs)) {
            print("\(who) is sliding down the dinosaur tail. Task #\(attemptNo) all done!")
            s.signal()
            dg.leave()
       }
   }
}
go()
dg.notify(queue: .global(), execute: {print("Everyone is done.")})

示例输出:

Emmie wants to work, will wait 4.674405654828654 seconds, attempt #1
Lily wants to work, will wait 1.5898288206500877 seconds, attempt #1
Wiley wants to work, will wait 1.2182416407288 seconds, attempt #1
Lily wants to work, will wait 3.3225083978280647 seconds, attempt #2
Everyone is done.
Wiley wants to work, will wait 2.801577828588925 seconds, attempt #2
Emmie wants to work, will wait 8.9696422949966 seconds, attempt #2
Lily went to work for 3 seconds on task #2
Wiley was denied. No soup for me! Task #1 not going to happen.
Lily was denied. No soup for me! Task #1 not going to happen.
Wiley was denied. No soup for me! Task #2 not going to happen.
Lily is sliding down the dinosaur tail. Task #2 all done!
Emmie went to work for 3 seconds on task #1
Emmie is sliding down the dinosaur tail. Task #1 all done!
Emmie went to work for 2 seconds on task #2
Emmie is sliding down the dinosaur tail. Task #2 all done!

在这种情况下,“每个人都完成了”几乎是立即发生的,因为 .leave 伴随着没有得到信号量或在“工作”完成之后,这没有意义。请帮忙。

最佳答案

您的主要问题是您在错误的地方调用了 dg.enter()。您总是希望在异步调用之前调用 enter(),并希望在异步调用完成时调用 leave()

在编写代码时,for 循环在第一次调用 enter 之前完成,这就是触发 notify 的原因立即。

func doWork(attemptNo: Int, who: String, secs: TimeInterval) -> Void {
    dg.enter()
    DispatchQueue.global().async {
        print("\(who) wants to work, will wait \(secs) seconds, attempt #\(attemptNo)")
        if s.wait(timeout: .now() + secs) == .timedOut {
            print("\(who) was denied. No soup for me! Task #\(attemptNo) not going to happen.")
            dg.leave()
            return
        }
        let workSecs = UInt32(Int.random(in: 1...3))
        print("\(who) went to work for \(workSecs) seconds on task #\(attemptNo)")
        sleep(workSecs)
        print("\(who) is sliding down the dinosaur tail. Task #\(attemptNo) all done!")
        s.signal()
        dg.leave()
    }
}

您的代码还奇怪地使用了信号量和 sleep 。我想这是模拟长时间运行的后台进程的尝试。

关于swift - DispatchGroup 通知 block 被提前调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54367351/

有关swift - DispatchGroup 通知 block 被提前调用的更多相关文章

  1. ruby-on-rails - Rails 常用字符串(用于通知和错误信息等) - 2

    大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje

  2. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  3. ruby-on-rails - Enumerator.new 如何处理已通过的 block ? - 2

    我在理解Enumerator.new方法的工作原理时遇到了一些困难。假设文档中的示例:fib=Enumerator.newdo|y|a=b=1loopdoy[1,1,2,3,5,8,13,21,34,55]循环中断条件在哪里,它如何知道循环应该迭代多少次(因为它没有任何明确的中断条件并且看起来像无限循环)? 最佳答案 Enumerator使用Fibers在内部。您的示例等效于:require'fiber'fiber=Fiber.newdoa=b=1loopdoFiber.yieldaa,b=b,a+bendend10.times.m

  4. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  5. c# - 如何在 ruby​​ 中调用 C# dll? - 2

    如何在ruby​​中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL

  6. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  7. ruby - 调用其他方法的 TDD 方法的正确方法 - 2

    我需要一些关于TDD概念的帮助。假设我有以下代码defexecute(command)casecommandwhen"c"create_new_characterwhen"i"display_inventoryendenddefcreate_new_character#dostufftocreatenewcharacterenddefdisplay_inventory#dostufftodisplayinventoryend现在我不确定要为什么编写单元测试。如果我为execute方法编写单元测试,那不是几乎涵盖了我对create_new_character和display_invent

  8. ruby - 在匿名 block 中产生 - 2

    我没有理解以下行为(另请参阅inthisSOthread):defdef_testputs'def_test.in'yieldifblock_given?puts'def_test.out'enddef_testdoputs'def_testok'endblock_test=procdo|&block|puts'block_test.in'block.callifblockputs'block_test.out'endblock_test.calldoputs'block_test'endproc_test=procdoputs'proc_test.in'yieldifblock_gi

  9. ruby-on-rails - 如何在发布新的 Ruby 或 Rails 版本时收到通知? - 2

    有人知道在发布新版本的Ruby和Rails时收到电子邮件的方法吗?他们有邮件列表,RubyonRails有一个推特,但我不想听到那些随之而来的喧嚣,我只想知道什么时候发布新版本,尤其是那些有安全修复的版本。 最佳答案 从therailsblog获取提要.http://weblog.rubyonrails.org/feed/atom.xml 关于ruby-on-rails-如何在发布新的Ruby或Rails版本时收到通知?,我们在StackOverflow上找到一个类似的问题:

  10. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

随机推荐