[英]Observe URLSession operation queue count?
我以这种方式使用URLSession
设置:
public struct NetworkSession {
public var session: URLSession
public let sessionOperationQueue = OperationQueue()
public init() {
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 20
sessionOperationQueue.maxConcurrentOperationCount = OperationQueue.defaultMaxConcurrentOperationCount
sessionOperationQueue.qualityOfService = .userInitiated
session = URLSession(configuration: sessionConfiguration, delegate: nil, delegateQueue:sessionOperationQueue)
}
.....
}
我想观察队列中找到的任务数。
我尝试使用组合:
sessionOperationQueue.publisher(for: \.operationCount).sink { count in
print("operations count: \(count)")
}
.store(in: &subscribers)
但这只会在初始化时打印0
并且永远不会在请求开始和完成时更新。
如何监控队列中找到的任务数量?
tl;博士
观察会话队列上的操作计数不会达到您想要的效果。
URLSession
代码中,队列用于单个委托方法,而不是包装整个请求-响应。async
- await
再现,则根本不使用操作队列(鉴于先前的观察,这是没有实际意义的)。 最重要的是,虽然URLSession
有一种方法可以查询正在进行的待处理请求,但它没有,AFAIK,对此具有可观察的属性(当然,除非您放弃完成处理程序并仅使用委托再现)。 因此,如果您想动态跟踪未决请求的计数,只需自己跟踪即可。 异步自定义Operation
子类模式似乎有点矫枉过正(但在本答案的Operation
部分中有概述)。 最简单的方法是通过一种方法简单地路由我的所有网络请求,该方法在请求进入时递增计数器并在完成时递减它。
带有代码示例的长答案
您可以使用 KVO 观察队列的operationCount
的变化(见下文),但这不会达到您想要的效果。 这不是包装整个网络请求和响应的操作,而是针对单个会话委托和完成处理程序回调的单个操作。
例如,考虑:
class ViewController: UIViewController {
lazy var session: URLSession = {
let configuration = URLSessionConfiguration.default
configuration.timeoutIntervalForRequest = 20
return URLSession(configuration: configuration, delegate: nil, delegateQueue: queue)
}()
let queue: OperationQueue = {
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 1
queue.qualityOfService = .userInitiated
return queue
}()
var observer: NSKeyValueObservation?
override func viewDidLoad() {
super.viewDidLoad()
observer = queue.observe(\.operationCount, options: .new) { queue, change in
print("Observer reported operationCount =", change.newValue!)
}
for i in 1000..<1010 {
let url = URL(string: "https://httpbin.org/get?value=\(i)")!
session.dataTask(with: url) { data, _, error in
guard let data = data else {
print(error ?? URLError(.badServerResponse))
return
}
print("Request", i, "returned", data.count, "bytes")
}.resume()
}
}
}
这会产生:
Observer reported operationCount = 1
Observer reported operationCount = 2
Observer reported operationCount = 3
Request 1000 returned 405 bytes
Observer reported operationCount = 4
Observer reported operationCount = 3
Request 1002 returned 405 bytes
Observer reported operationCount = 2
Request 1004 returned 405 bytes
Observer reported operationCount = 1
Request 1001 returned 405 bytes
Observer reported operationCount = 0
Observer reported operationCount = 1
Observer reported operationCount = 2
Request 1006 returned 405 bytes
Observer reported operationCount = 3
Observer reported operationCount = 2
Observer reported operationCount = 3
Request 1005 returned 405 bytes
Observer reported operationCount = 4
Observer reported operationCount = 3
Observer reported operationCount = 4
Request 1003 returned 405 bytes
Observer reported operationCount = 3
Request 1008 returned 405 bytes
Observer reported operationCount = 2
Request 1007 returned 405 bytes
Observer reported operationCount = 1
Request 1009 returned 405 bytes
Observer reported operationCount = 0
请注意,您永远不会看到它承认有十个请求待处理。 operationCount
报告委托队列上的内容,这不是您要查找的内容。
顺便说一句,在上面,委托队列是串行的(如文档中所述)。 它是一个允许并发网络请求的串行队列这一事实进一步证明,不存在包装整个请求的操作,而是针对单个委托回调的操作。
顺便说一句,如果您使用新的async
- await
URLSession
方法,则根本不会使用操作队列。 这是有道理的(考虑到它正在使用新的并发系统),但此时文档中没有说明。 无论如何,以下内容不会触发任何操作计数更改:
func startRequests() async throws {
try await withThrowingTaskGroup(of: Void.self) { group in
for i in 0..<4 {
let url = URL(string: "https://httpbin.org/get?value=\(i)")!
group.addTask {
let (data, _) = try await self.session.data(from: url)
print("Request", i, "returned", data.count, "bytes")
}
}
try await group.waitForAll()
}
}
但这没有实际意义,因为URLSession
操作队列无论如何都无法实现您想要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.