Multithreading Swift中具有并发性的功能/代码设计
我正在尝试在Swift中创建我的第一个应用程序,它涉及到向一个网站发出多个请求。这些请求都是使用块完成的Multithreading Swift中具有并发性的功能/代码设计,multithreading,swift,concurrency,nsurlsession,Multithreading,Swift,Concurrency,Nsurlsession,我正在尝试在Swift中创建我的第一个应用程序,它涉及到向一个网站发出多个请求。这些请求都是使用块完成的 var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in ... } task.resume() 据我所知,此块使用的线程与主线程不同 我的问题是,设计依赖于该块中的值的代码的最佳方法是什么?例如,
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in ... }
task.resume()
据我所知,此块使用的线程与主线程不同
我的问题是,设计依赖于该块中的值的代码的最佳方法是什么?例如,理想的设计(但由于执行这些块的线程不是主线程,因此不可能实现)是
但是,在上述设计中,最有可能的是getNames()和getEmails()将返回nil,因为任务在返回时不会更新电子邮件/名称
另一种设计(我目前正在实施)是有效地删除“prepareEmails”功能,并在任务功能中按顺序执行所有操作
func prepareEmails() {
getNames()
}
func getNames() {
...
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
getEmails(names)
})
task.resume()
}
func getEmails(names: NSArray) {
...
var task = NSURLSession.sharedSession().dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
sendEmails(emails, names)
})
task.resume()
}
有没有比后者更有效的设计?这是我第一次体验并发,因此任何建议都将不胜感激。调用具有
completionHandler
参数的异步方法时,典型的模式是自己使用completionHandler
闭包模式。因此,这些方法不返回任何内容,而是使用返回的信息作为参数调用闭包:
func getNames(completionHandler:(NSArray!)->()) {
....
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {data, response, error -> Void in
let names = ...
completionHandler(names)
}
task.resume()
}
func getEmails(completionHandler:(NSArray!)->()) {
....
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {data, response, error -> Void in
let emails = ...
completionHandler(emails)
}
task.resume()
}
然后,如果您需要按照代码示例的建议按顺序执行这些操作(即,如果电子邮件的检索取决于getNames
返回的名称),您可以执行以下操作:
func prepareEmails() {
getNames() { names in
getEmails() {emails in
sendEmails(names, emails) // I'm assuming the names and emails are in the input to this method
}
}
}
或者,如果它们可以同时运行,那么您应该这样做,因为这样会更快。诀窍是如何使第三个任务依赖于另外两个异步任务。两种传统的替代方案包括
NSOperation
,然后根据其他两个操作创建第三个任务。这可能超出了问题的范围,但您可以参考《并发编程指南》的一节,或参阅的异步与同步操作和子类化注释部分NSArray
,而是使用String
对象数组(例如[String]
)。此外,我还加入了错误处理,如果其中一个失败,我将返回错误的性质。但希望这说明了(a)使用completionHandler
块编写自己的方法所涉及的概念;和(b)根据其他两个异步任务的完成情况调用第三位代码。上述答案(特别是Rob基于DispatchQueue的答案)描述了并行运行两个任务并对结果作出响应所需的并发概念。为了清晰起见,答案缺乏错误处理,因为传统上,并发问题的正确解决方案非常冗长
对我来说不是这样
此代码段管理所有并发,将所有错误路由到
handleErrorFunc
,看起来就像所需的并发模式。完美。非常感谢
func prepareEmails() {
getNames() { names in
getEmails() {emails in
sendEmails(names, emails) // I'm assuming the names and emails are in the input to this method
}
}
}
func prepareEmails() {
let group = dispatch_group_create()
var emails: NSArray!
var names: NSArray!
dispatch_group_enter(group)
getNames() { results in
names = results
dispatch_group_leave(group)
}
dispatch_group_enter(group)
getEmails() {results in
emails = results
dispatch_group_leave(group)
}
dispatch_group_notify(group, dispatch_get_main_queue()) {
if names != nil && emails != nil {
self.sendEmails(names, emails)
} else {
// one or both of those requests failed; tell the user
}
}
}
HoneyBee.start()
.setErrorHandler(handleErrorFunc)
.branch {
$0.chain(getNames)
+
$0.chain(getEmails)
}
.chain(sendEmails)