我正在尝试跟踪当前异步网络请求的数量,并仅在有一个或多个请求正在进行时显示事件指示器。我正在使用调度组,但我认为我在 dispatch_group_notify block 和我的 closure block 之间存在竞争条件,因为我偶尔会在 dispatch_group_leave 上崩溃(任务组)行:
fatal error: unexpectedly found nil while unwrapping an Optional value
我认为发生这种情况是因为当调度组中没有更多项目时,它有时没有及时释放(设置为 nil),在它被后面的请求使用之前(而不是正在创建的新组)。然后,该组立即通知它为空,回调闭包被调用,它被设置为nil,但是还有一个额外的项目试图离开现在的nil 组。
我认为解决方案在于确保 dispatch_group_leave 在最后一个 dispatch_group_leave 被触发后立即触发它的 block ,即在 callback 关闭之前。
我尝试将 dispatch_group_leave 和 callback 代码包装在单独的 dispatch_sync 闭包中,然后将它们添加到自定义串行队列中,但问题仍然存在在所有处决的 50% 以上。
将 callback 闭包调用包装在主队列的 dispatch_async 中(如下面的代码所示)会有所帮助,但问题仍然存在于大约 10% 的队列中所有处决。
这是我的代码(复制粘贴到 Playground 进行测试):
import UIKit
import XCPlayground
// Allow for asynchronous execution to take as long as it likes
XCPlaygroundPage.currentPage.needsIndefiniteExecution = true
// Background container view
let view = UIView(frame: CGRectMake(0, 0, 100, 100))
view.backgroundColor = UIColor.blackColor()
XCPlaygroundPage.currentPage.liveView = view
// Our activity indicator
let activityIndicator = UIActivityIndicatorView()
view.addSubview(activityIndicator)
activityIndicator.center = view.center
// Used to keep track of the number of current tasks
var taskGroup: dispatch_group_t!
// An async task that calls its callback after 2 to 5 seconds
func fireATask(callback: String -> Void) {
if taskGroup == nil {
print("Creating new dispatch group")
taskGroup = dispatch_group_create()
dispatch_group_enter(taskGroup)
activityIndicator.startAnimating()
dispatch_group_notify(taskGroup, dispatch_get_main_queue()) {
activityIndicator.stopAnimating()
taskGroup = nil
print("All done!")
}
} else {
print("Using existing dispatch group")
dispatch_group_enter(taskGroup)
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
let delay = arc4random_uniform(1) + 2
print("Task fired with [\(delay)] second delay.")
let delayNanoseconds = Int64(UInt64(delay) * NSEC_PER_SEC)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delayNanoseconds), dispatch_get_main_queue()) {
dispatch_group_leave(taskGroup) // Sometimes crashing here because taskGroup is nil
dispatch_async(dispatch_get_main_queue()) { // My attempt to make sure dispatch_group_notify is called before the callback
callback("Task with [\(delay)] second delay finished!")
}
}
}
}
我有时会得到很好的结果:
Creating new dispatch group
Using existing dispatch group
Task fired with [2] second delay.
Task fired with [2] second delay.
Task with [2] second delay finished!
All done!
Task with [2] second delay finished!
Creating new dispatch group
Task fired with [2] second delay.
All done!
Task with [2] second delay finished!
其他时候我会崩溃:
Creating new dispatch group
Using existing dispatch group
Task fired with [2] second delay.
Task fired with [2] second delay.
Task with [2] second delay finished!
Using existing dispatch group
Task fired with [2] second delay.
All done!
Task with [2] second delay finished!
fatal error: unexpectedly found nil while unwrapping an Optional value
最佳答案
dispatch_group_notify 安排一个 block 对象在组为空时提交到队列。因此,在您的第二个示例中,您遇到了崩溃。由于从不同线程异步调用 print,日志中的消息出现乱序。这是真实情况:
Creating new dispatch group
Using existing dispatch group
Task fired with [2] second delay.
Task fired with [2] second delay.
Task with [2] second delay finished!
Task with [2] second delay finished!
All done!
Using existing dispatch group
Task fired with [2] second delay.
Task with [2] second delay finished!
fatal error: unexpectedly found nil while unwrapping an Optional value
只需使用 dispatch_sync(dispatch_get_main_queue()) 包装所有 print 调用,您将得到类似的结果。
这里是我解决问题的方式:
// The execution queue
var tasksQueue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)
var nTasks = 0
// An async task that calls its callback after 2 to 5 seconds
func fireATask(callback: String -> Void) {
dispatch_async(tasksQueue) {
dispatch_sync(dispatch_get_main_queue()) {
nTasks += 1
activityIndicator.startAnimating()
}
let delay = arc4random_uniform(1) + 2
print("Task fired with [\(delay)] second delay.")
let delayNanoseconds = Int64(UInt64(delay) * NSEC_PER_SEC)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delayNanoseconds), dispatch_get_main_queue()) {
callback("Task with [\(delay)] second delay finished!")
nTasks -= 1
if nTasks == 0 {
activityIndicator.stopAnimating()
print("All done!")
}
}
}
}
关于ios - GCD - 跟踪总数或异步任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37507038/
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby中使用两个参数异步运行exe吗?我已经尝试过ruby命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何rubygems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除
如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
我写了一个非常简单的rake任务来尝试找到这个问题的根源。namespace:foodotaskbar::environmentdoputs'RUNNING'endend当在控制台中执行rakefoo:bar时,输出为:RUNNINGRUNNING当我执行任何rake任务时会发生这种情况。有没有人遇到过这样的事情?编辑上面的rake任务就是写在那个.rake文件中的所有内容。这是当前正在使用的Rakefile。requireFile.expand_path('../config/application',__FILE__)OurApp::Application.load_tasks这里
在我做的一些网络开发中,我有多个操作开始,比如对外部API的GET请求,我希望它们同时开始,因为一个不依赖另一个的结果。我希望事情能够在后台运行。我找到了concurrent-rubylibrary这似乎运作良好。通过将其混合到您创建的类中,该类的方法具有在后台线程上运行的异步版本。这导致我编写如下代码,其中FirstAsyncWorker和SecondAsyncWorker是我编写的类,我在其中混合了Concurrent::Async模块,并编写了一个名为“work”的方法来发送HTTP请求:defindexop1_result=FirstAsyncWorker.new.async.
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上
我以前没有使用过cron,所以我不能确定我这样做是对的。我想要自动化的任务似乎没有运行。我在终端中执行了这些步骤:sudogeminstall每当切换到应用程序目录无论何时。(这创建了文件schedule.rb)我将此代码添加到schedule.rb:every10.minutesdorunner"User.vote",environment=>"development"endevery:hourdorunner"Digest.rss",:environment=>"development"end我将此代码添加到deploy.rb:after"deploy:symlink","depl