繁体   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