Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/34.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
Swift调度队列:串行或并行_Swift_Multithreading_Concurrency_Grand Central Dispatch - Fatal编程技术网

Swift调度队列:串行或并行

Swift调度队列:串行或并行,swift,multithreading,concurrency,grand-central-dispatch,Swift,Multithreading,Concurrency,Grand Central Dispatch,在我的应用程序中,我必须在后台同时解压多个文件。哪种代码在多个线程上并行执行compressedFiles数组: for file in compressedFiles { DispatchQueue.global(qos: .userInteractive).async { let work = DispatchGroup() work.enter() file.decompress() work.leave() } } 或: 此外,如果我希望在某个文

在我的应用程序中,我必须在后台同时解压多个文件。哪种代码在多个线程上并行执行compressedFiles数组:

for file in compressedFiles {
  DispatchQueue.global(qos: .userInteractive).async {
    let work = DispatchGroup()
    work.enter()
    file.decompress()
    work.leave()
  }
}
或:

此外,如果我希望在某个文件解压缩过程完成后收到通知,如何利用DispatchGroup类?将wait()和notify()放在何处


谢谢。

调度组需要在循环外部,每个
输入
都需要在循环内部,但在包含
离开
的线程外部。但是整个代码也需要在它自己的调度队列中,因为您不能阻塞(等待)主队列

let queue = DispatchQueue(label:"myqueue")
queue.async {
    let work = DispatchGroup()
    for file in compressedFiles {
        work.enter()
        DispatchQueue.global(qos: .userInteractive).async {
            file.decompress()
            work.leave()
        }
    }
    work.notify... // get on main thread here?
}

第二个示例将按顺序运行它们。它只做一次调度,一个接一个地运行它们。第一个示例将并行运行它们,将每个线程分派到不同的工作线程。但不幸的是,两者都没有正确使用调度组

关于调度组,您应该在循环之前定义它,并在调用
async
之前输入
。但是,只有从
async
调用中调用异步进程时,才需要手动调用
enter
leave
。但鉴于
解压
可能是一个同步过程,您只需将组提供给
异步
,它将为您处理所有事情:

let group = DispatchGroup()

for file in compressedFiles {
    DispatchQueue.global(qos: .userInteractive).async(group: group) {
        file.decompress()
    }
}

group.notify(queue: .main) {
    // all done
}

但是,并行示例中存在一个更深层次的问题,而不是担心调度组逻辑。具体来说,它会受到线程爆炸的影响,线程爆炸可能会超过CPU上可用的内核数。更糟糕的是,如果您有很多文件要解压缩,您甚至可以超过GCD池中工作线程的有限数量。当这种情况发生时,它可以防止在GCD上运行任何其他服务质量。相反,您希望并行运行它,但您希望在享受并行性的同时将其限制在合理的并发程度,以避免耗尽其他任务的资源

如果您想让它并行运行,但又避免线程爆炸,您通常会使用它。这提供了CPU支持的最大并行性,但防止了线程爆炸可能导致的问题:

DispatchQueue.global(qos: .userInitiated).async {
    DispatchQueue.concurrentPerform(iterations: compressedFiles.count) { index in
        compressedFiles[index].decompress()
    }
    
    DispatchQueue.main.async {
        // all done
    }
}
这将把并行性限制到设备上内核允许的最大值。它还消除了对调度组的需要


或者,如果您希望享受并行性,但并发度较低(例如,为了让一些内核可用于其他任务,以最小化峰值内存使用率等),您可以使用操作队列和
maxConcurrentOperationCount

let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4  // a max of 4 decompress tasks at a time

let completion = BlockOperation {
    // all done
}

for file in compressedFiles {
    let operation = BlockOperation {
        file.decompress()
    }
    completion.addDependency(operation)
    queue.addOperation(operation)
}

OperationQueue.main.addOperation(completion)

或者matt指出,在iOS 13(或macOS 10.15)及更高版本中,您可以:

let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4

for file in compressedFiles {
    queue.addOperation {
        file.decompress()
    }
}

queue.addBarrierBlock {
    DispatchQueue.main.async {
        // all done
    }
}

DispatchGroup的启动不应该在for循环中以并行方式创建多个线程,即每个文件一个线程吗?对于notify()?是的,我的回答完全基于OP的原始代码(“哪个代码”)的体系结构和明确的目标(“在多个线程上并行执行压缩文件数组”)。OP没有问这是不是一个好主意。顺便说一句,我可能会建议
.userInitiated
.utility
QoS,而不是
.userInteractive
。是的,“新”就是这个意思。我只是说现在它已经存在了,很酷。
let queue = OperationQueue()
queue.maxConcurrentOperationCount = 4

for file in compressedFiles {
    queue.addOperation {
        file.decompress()
    }
}

queue.addBarrierBlock {
    DispatchQueue.main.async {
        // all done
    }
}