Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
iOS URL请求。信号量问题_Ios_Swift_Concurrency_Semaphore - Fatal编程技术网

iOS URL请求。信号量问题

iOS URL请求。信号量问题,ios,swift,concurrency,semaphore,Ios,Swift,Concurrency,Semaphore,我正在进行并发编程,其中有一些信号量问题。 我的函数首先从服务器加载数据,分析接收到的信息,然后在必要时向服务器发出第二个请求 我尝试了不同的方法让它运行,但没有一个做得很好。 我当前的代码似乎是正确的,但在第二次请求时它只是锁定(可能像死锁一样),最后一个日志是“{taskIdentifier:2}{suspended}” 请告诉我我不知道什么。也许有更优雅的方式来处理这些目的 提前谢谢你 var users = [Int]() let linkURL = URL.init(string: "

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

我尝试了不同的方法让它运行,但没有一个做得很好。 我当前的代码似乎是正确的,但在第二次请求时它只是锁定(可能像死锁一样),最后一个日志是“{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)

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

这是死锁,因为您正在等待
URLSession
delegateQueue
上的信号量。默认代理队列不是主队列,但它是一个串行后台队列(即
OperationQueue
,其
maxConcurrentOperationCount
1
)。因此,您的代码正在同一个串行队列上等待一个信号量,该队列本应向该信号量发送信号

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

  • 不要使用
    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)
    
  • 或者,您可以通过将关闭信号量的代码分派到其他队列来解决此问题,例如

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

  • 为了完整性起见,我要指出,您可能根本不应该使用信号量来发出这些请求,因为发出一系列连续的请求将导致严重的性能损失(另外,您正在阻止一个线程,这通常是不鼓励的)


    这段代码的重构要做的更多一些。它基本上需要发出一系列并发请求,可能使用“下载”任务而不是“数据”任务来最小化内存影响,然后当所有请求都完成时,根据需要在最后将其拼凑在一起(由
    操作
    “完成”操作或调度组通知触发).

    为什么需要信号灯?基本上,您需要在第一个调用的闭包内运行第二个服务器请求,第二个闭包(内部闭包)应该通过另一个闭包发送结果。如果您认为它是您所需要的,我会给您一个代码剪贴。@OhadM,因为我正确地理解它,闭包运行在不同的线程上,所以主线程不会等待闭包中的代码完成。在我的情况下,它甚至没有开始执行。操场就停了。这就是我使用信号量的原因。如果您告诉闭包在不同的线程上运行,那么闭包将在不同的线程上运行。因此,它们也可以在主线程上运行。2.你们为什么使用操场?你需要在整个应用程序中测试你的代码environment@OhadM在操场上,我测试我的应用程序模块,这比编译整个应用程序要快。好的,闭包默认在后台运行,要在主线程上运行它,我只需要使用dispatch..get_global_queue告诉它,并将其设置为两次:第一个请求和第二个?闭包在创建它们的线程上运行,除非函数显式调用另一个线程上的回调。在这种情况下,除非您告诉他们其他情况,否则所有这些都将在主线程上运行。