I have an App which does hundreds of different network calls (HTTP GET requests) to a REST service. The calls are done from every single page of the app and there are much of them. But there is the requirement that two requests have to be done (on startup or awake) before any other network requests happens. The result of these two requests is some config data which is needed before all other following requests. (this requirement has many reason)
我有一个应用程序,可以对REST服务进行数百种不同的网络调用(HTTP GET请求)。这些电话来自应用的每一个页面,而且有很多。但是,在任何其他网络请求发生之前,有两个请求必须完成(启动或唤醒)。这两个请求的结果是在所有后续请求之前需要的一些配置数据。(这个要求有很多原因)
I have one central method for all GET requests. It uses AFNetworking and (of course) asynchronous handlers:
对于所有GET请求,我有一个中心方法。它使用AFNetworking和(当然)异步处理程序:
func GET(path: String, var parameters: Dictionary<String, String>? = nil) -> Future<AnyObject!> {
let promise = Promise<AnyObject!>()
manager.GET(path, parameters: parameters, success: { (task: NSURLSessionDataTask!, response: AnyObject!) -> Void in
// some processing...
promise.success(response)
}) { (task: NSURLSessionDataTask!, error: NSError!) -> Void in
// some failure handling...
promise.failure(error)
}
return promise.future
}
The problem now is - how to do this first two calls and block all other calls until those two succeed? The obvious solution would be a semaphore which blocks the thread (not main!) until those two calls arrive successfully but if possible I want to avoid this solution. (because of deadlocks, race conditions, how to do error handling, etc... the usual suspects)
现在的问题是——如何执行前两个调用并阻止其他所有调用,直到这两个成功?明显的解决方案是一个信号量,它会阻塞线程(不是main!),直到这两个调用成功到达,但是如果可能的话,我想要避免这个解决方案。(由于死锁、竞态条件、如何进行错误处理等原因……)通常的嫌疑人)
So is there any better solution for this?
有更好的解决方法吗?
The synchronous order basically has to be:
同步顺序主要是:
- 1st call
- 1日叫
- wait for successful response of 1st call
- 等待第一个电话成功回复
- 2nd call
- 2日叫
- wait or successful response of 2nd call
- 等待或成功回复第二次电话
- allow all other calls (async) in any order
- 允许以任何顺序进行所有其他调用(异步)
I can not do this logic on the upper layers of the app because the GET requests could come from every part of the app, so I would need to rewrite everthing. I want to do it centrally on this single GET request.
我不能在应用的上层执行这种逻辑,因为GET请求可能来自于应用的每个部分,所以我需要重写所有内容。我想集中在这个单一的GET请求上。
Maybe this is also possible with the Promise/Future pattern I already use, any hints are welcome.
也许我已经使用了Promise/Future模式,这也是可能的,任何提示都是受欢迎的。
Thanks.
谢谢。
1 个解决方案
#1
2
There are a couple of approaches to tackle this class of problem:
有几种方法可以解决这类问题:
- You can use GCD (as shown in the answer you linked to) using semaphores or dispatch groups.
- 您可以使用信号量或分派组使用GCD(如图所示)。
- You can use asynchronous
NSOperation
custom subclass in conjunction withNSOperationQueue
. - 您可以将异步NSOperation自定义子类与NSOperationQueue结合使用。
- Or you can use promises.
- 或者你可以使用承诺。
But I'd generally suggest you pick one of these three, but don't try to introduce dispatch/operation queue patterns with your existing futures/promises code. People will suggest dispatch/operation queue approaches simply because this is how one generally solves this type of problem (using futures is not gained popular acceptance yet, and there are competing promises/futures libraries out there). But promises/futures is designed to solve precisely this problem, and if you're using that, just stick with it.
但我一般建议您选择这三种类型中的一种,但不要试图使用现有的期货/承诺代码引入分派/操作队列模式。人们会建议调度/操作队列方法,仅仅是因为这是一种解决这类问题的方法(使用期货还没有得到普遍接受,而且还有相互竞争的承诺/期货库)。但是承诺/期货的设计就是为了解决这个问题,如果你使用它,就坚持下去。
On the specifics of the dispatch/operation approaches, I could explain why I don't like the GCD approach and try to convince you to use the NSOperationQueue
approach, but that's moot if you're using promises/futures.
关于分派/操作方法的细节,我可以解释为什么我不喜欢GCD方法,并试图说服您使用NSOperationQueue方法,但如果您使用的是promise /futures,那么这是没有意义的。
The challenge here, though, is that you appear to be using an old version of Thomvis/BrightFutures. The current version takes two types for the generic. So my code below probably won't work for you. But I'll offer it up as as suggestion, as it may be illustrative.
然而,这里的挑战在于,你似乎在使用一个旧版本的托马斯/布莱特期货。当前版本需要两种类型的通用类型。所以我下面的代码可能对你不起作用。但我将把它作为建议提供给大家,因为它可能具有说明性。
For example, let's imagine that you had a loginURL
(the first request), and some second request that you wanted to perform after that, but then had an array urls
that you wanted to run concurrently with respect to each other, but only after the first two requests were done. Using 3.2.2 of BrightFutures, it might look like:
例如,让我们假设您有一个loginURL(第一个请求),以及在此之后想要执行的另一个请求,然后有一个数组url,您希望在彼此之间并发运行,但必须在前两个请求完成之后。使用BrightFutures的3.2.2,它可能是:
GET(loginURL).flatMap { responseObject -> Future<AnyObject!, NSError> in
return self.GET(secondRequestURL)
}.flatMap { responseObject -> Future<Int, NSError> in
return urls.map { self.GET($0) }.fold(0) { sum, _ in sum + 1 }
}.onSuccess { count in
print("\(count) concurrent requests completed successfully")
}.onFailure { error in
print("not successful: \(error)")
}
Judging from your code snippet, you must be using an old version of BrightFutures, so the above probably won't work as written, but hopefully this illustrates the basic idea. Use the capabilities of BrightFutures to manage these asynchronous tasks and control which are done sequentially and which are done concurrently.
从您的代码片段判断,您必须使用一个旧版本的BrightFutures,所以上面可能不会写,但希望这说明了基本思想。使用BrightFutures的功能来管理这些异步任务和控制,这些任务和控制是按顺序执行的,同时执行。
#1
2
There are a couple of approaches to tackle this class of problem:
有几种方法可以解决这类问题:
- You can use GCD (as shown in the answer you linked to) using semaphores or dispatch groups.
- 您可以使用信号量或分派组使用GCD(如图所示)。
- You can use asynchronous
NSOperation
custom subclass in conjunction withNSOperationQueue
. - 您可以将异步NSOperation自定义子类与NSOperationQueue结合使用。
- Or you can use promises.
- 或者你可以使用承诺。
But I'd generally suggest you pick one of these three, but don't try to introduce dispatch/operation queue patterns with your existing futures/promises code. People will suggest dispatch/operation queue approaches simply because this is how one generally solves this type of problem (using futures is not gained popular acceptance yet, and there are competing promises/futures libraries out there). But promises/futures is designed to solve precisely this problem, and if you're using that, just stick with it.
但我一般建议您选择这三种类型中的一种,但不要试图使用现有的期货/承诺代码引入分派/操作队列模式。人们会建议调度/操作队列方法,仅仅是因为这是一种解决这类问题的方法(使用期货还没有得到普遍接受,而且还有相互竞争的承诺/期货库)。但是承诺/期货的设计就是为了解决这个问题,如果你使用它,就坚持下去。
On the specifics of the dispatch/operation approaches, I could explain why I don't like the GCD approach and try to convince you to use the NSOperationQueue
approach, but that's moot if you're using promises/futures.
关于分派/操作方法的细节,我可以解释为什么我不喜欢GCD方法,并试图说服您使用NSOperationQueue方法,但如果您使用的是promise /futures,那么这是没有意义的。
The challenge here, though, is that you appear to be using an old version of Thomvis/BrightFutures. The current version takes two types for the generic. So my code below probably won't work for you. But I'll offer it up as as suggestion, as it may be illustrative.
然而,这里的挑战在于,你似乎在使用一个旧版本的托马斯/布莱特期货。当前版本需要两种类型的通用类型。所以我下面的代码可能对你不起作用。但我将把它作为建议提供给大家,因为它可能具有说明性。
For example, let's imagine that you had a loginURL
(the first request), and some second request that you wanted to perform after that, but then had an array urls
that you wanted to run concurrently with respect to each other, but only after the first two requests were done. Using 3.2.2 of BrightFutures, it might look like:
例如,让我们假设您有一个loginURL(第一个请求),以及在此之后想要执行的另一个请求,然后有一个数组url,您希望在彼此之间并发运行,但必须在前两个请求完成之后。使用BrightFutures的3.2.2,它可能是:
GET(loginURL).flatMap { responseObject -> Future<AnyObject!, NSError> in
return self.GET(secondRequestURL)
}.flatMap { responseObject -> Future<Int, NSError> in
return urls.map { self.GET($0) }.fold(0) { sum, _ in sum + 1 }
}.onSuccess { count in
print("\(count) concurrent requests completed successfully")
}.onFailure { error in
print("not successful: \(error)")
}
Judging from your code snippet, you must be using an old version of BrightFutures, so the above probably won't work as written, but hopefully this illustrates the basic idea. Use the capabilities of BrightFutures to manage these asynchronous tasks and control which are done sequentially and which are done concurrently.
从您的代码片段判断,您必须使用一个旧版本的BrightFutures,所以上面可能不会写,但希望这说明了基本思想。使用BrightFutures的功能来管理这些异步任务和控制,这些任务和控制是按顺序执行的,同时执行。