簡體   English   中英

觀察 URLSession 操作隊列數?

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM