[英]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.