iOS网址请求。信号量问题 [英] iOS URL Requests. Semaphore issues

查看:134
本文介绍了iOS网址请求。信号量问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm entering the concurrency programming with some semaphore issues. My function first loads data from server, analyze received info and then, if necessary, makes second request to server.

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

I tried different ways to make it run, none of them did it well. My current code FOR ME seems to be correct, but on second request it just locks(maybe like a DeadLock) and the last log is "<__NSCFLocalDataTask: 0x7ff470c58c90>{ taskIdentifier: 2 } { suspended }"

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

Please, tell me what do I don't know. Maybe there is more elegant way to work with completions for these purposes?

提前谢谢!

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为什么我这样做。服务器返回有限的数据计数。为了获得更多,我必须使用偏移量。

P.S. Why do I do it. Server returns limited count of data. To get more, I have to use offset.

推荐答案

这是死锁,因为你正在等待 URLSession 's delegateQueue 。默认委托队列不是主队列,但它是一个串行后台队列(即 OperationQueue ,带有 maxConcurrentOperationCount 1 )。因此,您的代码正在等待应该发信号通知信号量的同一串行队列上的信号量。

This is deadlocking because you are waiting for a semaphore on the URLSession's delegateQueue. The default delegate queue is not the main queue, but it is a serial background queue (i.e. an OperationQueue with a maxConcurrentOperationCount of 1). So your code is waiting for a semaphore on the same serial queue that is supposed to be signaling the semaphore.

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

The tactical fix is to make sure you're not calling wait on the same serial queue that the session's completion handlers are running on. There are two obvious fixes:


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

  1. Do not use shared session (whose delegateQueue is a serial queue), but rather instantiate your own URLSession and specify its delegateQueue to be a concurrent OperationQueue that you create:

let queue = OperationQueue()
queue.name = "com.domain.app.networkqueue"

let configuration = URLSessionConfiguration.default()
let session = URLSession(configuration: configuration, delegate: nil, delegateQueue: queue)


  • 或者,你可以解决这通过将信号量的代码发送到其他队列,例如

  • Alternatively, you can solve this by dispatching the code with the semaphore off to some other queue, e.g.

    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()
    







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


    For the sake of completeness, I'll note that you probably shouldn't be using semaphores to issue these requests at all, because you'll end up paying a material performance penalty for issuing a series of consecutive requests (plus you're blocking a thread, which is generally discouraged).

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

    The refactoring of this code to do that is a little more considerable. It basically entails issuing a series of concurrent requests, perhaps use "download" tasks rather than "data" tasks to minimize memory impact, and then when all of the requests are done, piece it all together as needed at the end (triggered by either a Operation "completion" operation or dispatch group notification).

    这篇关于iOS网址请求。信号量问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆