设置
我的程序中有两个区域-branch 1 和branch 2 -在其中每个区域一次异步发出1个并发GET请求的网络请求。每次发送1个请求,因为对于任何向服务器发出请求的用户,服务器的宽限期只有几毫秒。一次运行1个并发请求旨在帮助该宽限期。
进行此操作的目的是,如果在任何分支中任何请求失败,则可以再次重发该请求。
问题:
当我彼此分开运行这些分支时(即不同时运行),服务器很高兴。但是,一旦我允许两个操作同时发生,服务器就会引发429 错误,该错误是让用户知道there are too many requests coming in at any one time 的错误。然后发生的是一半的请求失败,然后由于故障安全,请求再次发送以进行处理,直到全部完成为止。 代表用户的数据包浪费时间和资源。
场景
Branch 1 发送10个请求(通常在数千个请求中,一次处理一个,但为简单起见,我们将其保持在10个)。 这10个请求将非常快地一次并发处理一次,并返回其适当的数据对象。
现在,如果我们再次运行branch 1 操作-并发10个请求,然后添加branch 2's 10个请求,这将创建20个请求操作-数量增加一倍-移出服务器,这将导致分支1和2的大约一半请求失败,然后启用故障保护以重新发送那些请求操作。号泣。
问题
不管这两个分支位于我的应用程序中的什么位置,有没有一种方法可以将这些请求操作从我的应用程序中传递出去,以便我们可以控制和限制发送到服务器的请求操作,从而不会对服务器造成轰炸仅对于一半的请求失败?
可能的解决方案
我曾经想到的一个想法是创建一个单例,该单例将充当队列以及瓶颈,使我可以在代码库中的任何位置添加来自任何分支的请求操作-因此,为什么我认为单例是一个好主意为此-然后,一旦意识到请求操作已添加到队列中,然后使该队列一次运行1个并发请求。
我认为这对于我的目的将非常有用,我只是不知道如何处理请求的完成块,因为Branch 1 的请求操作与Branch 2 的请求操作的完成块不同。
您将如何处理?我们可以做些什么吗?
编辑1-我目前在做什么
在分支1中-使用AFHTTPOperation:
1)对于每个进程,我创建一个for循环,该循环迭代10次,将10 AFHTTPRequestOperation 添加到名为NSMutableArray 类型的名为multiOperations的本地数组中。
2)然后我将multipleOperations数组添加到batchOfRequestOperations方法中,如下所示:
NSArray *operations = [AFURLConnectionOperation batchOfRequestOperations:muiltipleOperations
progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations){
//Do some stuff here for each iteration
}
completionBlock:^(NSArray*operations){
//Call the method that repeats this process again.
}];
3)然后将操作添加到mainQueue中,如下所示
[[NSOperationQueue mainQueue] addOperationsperations waitUntilFinished:NO];
我现在想知道分支一中的此过程是否甚至将其设置为1并发,看不到它是:\
在分支2中使用NSURLSessionDataTask(刚刚实现,如果它们都使用相同的子类,会不会更容易?lol
我注意到我正在使用AFHTTPSessionManager 创建NSURLSessionDataTasks ..该代码不会在for循环中运行,而是调用自己的方法,以便每次请求执行其自己的完成块时都会发出另一个请求。因此,分支2中的上一个请求完成后,它将永远永远保持自身调用。这就是我知道它一次仅运行1个请求的方式。这样很好。
无论如何,可以使它更清洁吗?
不,我在哪里使用HTTPRequestOperationManager 有人可以告诉我如何正确完成操作吗?
谢谢。
Best Answer-推荐答案 strong>
根据您的编辑,我可以看到您可能需要更改的一些内容。首先,是的,如果您同时使用AFHTTPOperation 或NSURLSessionDataTask ,但不同时使用两者,则将更加容易。
如果要使用AFHTTPOperation ,则不要对[NSOperationQueue mainQueue] 进行操作排队。原因是那是主要的UI队列,您不希望网络操作阻止它。您应该做的是创建自己的NSOperationQueue 并将其并发设置为1。
NSOperationQueue *networkQueue = [[NSOperationQueue alloc] init];
networkQueue.maxConcurrentOperationCount = 1;
使用您的单例想法将该队列存储在可以从应用程序中的任何位置访问的某个位置,这是确保您通过同一队列发送所有网络操作的好方法。
就是说,我建议将NSURLSessionDataTask 与AFHTTPSessionManager 一起使用而不是。 AFNetworking的文档状态:
针对iOS 7或Mac OS X 10.9或更高版本的开发人员 鼓励广泛使用Web服务进行子类化 AFHTTPSessionManager,提供一个返回共享的类方法 身份验证和其他配置可以在其上的单例对象 在整个应用程序中共享。
听起来这是完成所需内容的好方法。基本上,您将使用一个类方法创建AFHTTPSessionManager 的子类,该方法创建一个用自定义NSURLSessionConfiguration 初始化的实例。您可以配置NSURLSessionConfiguration ,但是它适合您的应用程序,但是您对此特定问题感兴趣的主要属性是 HTTPMaximumConnectionsPerHost :
此属性确定最大并发数 session 中基于此任务的任务与每个主机建立的连接 组态。
将其设置为1 ,您可以让AFHTTPSessionManager (实际上是NSURLSession )担心确保在任何给定时间仅对您的服务器发出一个请求。
遵循以下原则:
@interface AppHTTPSessionManager : AFHTTPSessionManager
+ (instancetype)appSession;
@end
@implementation AppHTTPSessionManager
+ (instancetype)appSession {
static AppHTTPSessionManager *_appSession = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPMaximumConnectionsPerHost = 1;
_appSession = [[AppHTTPSessionManager alloc] initWithSessionConfiguration:configuration];
});
return _appSession;
}
@end
然后,每当要进行网络 call 时,请确保从NSURLSessionDataTask 创建[AppHTTPSessionManager appSession] 。如果这样做,这些任务应该自动被限制为一次向服务器发出一个请求。
关于ios - AFNetworking请求操作-创建 channel /瓶颈队列单例,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/26689177/
|