iOSurl请求。 信号量问题

我正在进入带有一些信号量问题的并发编程。 我的函数首先从服务器加载数据,分析收到的信息,然后,如有必要,向服务器发出第二个请求。

我尝试了不同的方法让它运行,没有一个做得好。 我当前的代码FOR ME似乎是正确的,但在第二次请求它只是锁定(可能像死锁),最后一个日志是“ {taskIdentifier:2} {suspended}”

请告诉我我不知道的是什么。 也许有更优雅的方式来完成这些目的的完成?

先谢谢你!

var users = [Int]() let linkURL = URL.init(string: "https://bla bla") let session = URLSession.shared() let semaphore = DispatchSemaphore.init(value: 0) let dataRequest = session.dataTask(with:linkURL!) { (data, response, error) in let json = JSON (data: data!) if (json["queue"]["numbers"].intValue>999) { for i in 0...999 { users.append(json["queue"]["values"][i].intValue) } for i in 1...lround(json["queue"]["numbers"].doubleValue/1000) { let session2 = URLSession.shared() let semaphore2 = DispatchSemaphore.init(value: 0) let linkURL = URL.init(string: "https://bla bla") let dataRequest2 = session2.dataTask(with:linkURL!) { (data, response, error) in let json = JSON (data: data!) print(i) semaphore2.signal() } dataRequest2.resume() semaphore2.wait(timeout: DispatchTime.distantFuture) } } semaphore.signal() } dataRequest.resume() semaphore.wait(timeout: DispatchTime.distantFuture) 

PS为什么我这样做。 服务器返回有限的数据计数。 为了获得更多,我必须使用偏移量。

这是死锁,因为您正在等待URLSessiondelegateQueue上的信号量。 默认委托队列不是主队列,但它是一个串行后台队列(即maxConcurrentOperationCount1OperationQueue )。 所以你的代码正在等待同一个串口队列上的信号量,该队列应该用信号通知信号量。

战术修复是确保您没有在运行会话的完成处理程序的同一串行队列上调用wait 。 有两个明显的修复:

  1. 不要使用shared会话(其delegateQueue是一个串行队列),而是实例化您自己的URLSession并将其delegateQueue指定为您创建的并发OperationQueue

     let queue = OperationQueue() queue.name = "com.domain.app.networkqueue" let configuration = URLSessionConfiguration.default() let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: queue) 
  2. 或者,您可以通过将具有信号量的代码分配给其他队列来解决此问题,例如

     let mainRequest = session.dataTask(with: mainUrl) { data, response, error in // ... DispatchQueue.global(attributes: .qosUserInitiated).async { let semaphore = DispatchSemaphore(value: 0) for i in 1 ... n { let childUrl = URL(string: "https://blabla/\(i)")! let childRequest = session.dataTask(with: childUrl) { data, response, error in // ... semaphore.signal() } childRequest.resume() _ = semaphore.wait(timeout: .distantFuture) } } } mainRequest.resume() 

为了完整起见,我会注意到您可能根本不应该使用信号量来发出这些请求,因为您最终会因发出一系列连续请求而遭受重大性能损失(加上您阻止一个线程,通常不鼓励)。

这个代码的重构是为了做到这一点。 它基本上需要发出一系列并发请求,可能使用“下载”任务而不是“数据”任务来最小化内存影响,然后当所有请求完成时,根据需要将它们全部拼凑在一起(由任一个引发a Operation “完成”操作或调度组通知)。