微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ios – 使用dispatch_async在Swift中同时分析数组

我正在尝试使用GCD的后台线程同时分析照片.这是我写的代码

dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value),0)) {
    for (var i = 0; i < 8; i++)
    {
        let color = self.photoAnalyzer.analyzeColors(imageStrips[i])
        colorList.append(color)
    }
}

有关变量名称的说明,以下是它们的描述:

photoAnalyzer是我编写的一个名为Analyzer的类的实例,它包含处理图像的所有方法.

analyzeColors是Analyzer类中的一个方法,它执行大部分分析并返回一个字符串,其中包含传入图像的主色

imageStrips是UIImage的一个数组,构成了原始图像的各个部分

colorList是一个字符串数组,用于存储analyzeColor方法的每个部分的返回值.

上面的代码顺序运行,因为for循环一次只访问imageList中的一个图像.我想要做的是同时分析imageStrips中的每个图像,但我不知道如何去做.

任何建议将不胜感激.如果您希望看到所有代码以进一步帮助我,我可以发布一个GitHub链接.

编辑这是我同时处理8个处理器的更新代码.

dispatch_apply(8,imageQueue) { numStrips -> Void in
    let color = self.photoAnalyzer.analyzeColors(imageStrips[numStrips])
    colorList.append(color)
}

但是,如果我尝试使用超过8个代码实际上运行速度比顺序运行慢.

解决方法

有几种方法可以做到这一点,但在我们开始之前有几点意见:

>要尝试最大限度地提高性能,如果您进行任何并发处理,请注意不保证它们的完成顺序.因此,如果它们出现的顺序很重要,那么简单的colorList.append(颜色)模式将不起作用.您可以预先填充colorList,然后让每个迭代只执行colorList [i] = color,也可以使用字典. (显然,如果订单不重要,那么这并不重要.)
>因为这些迭代将同时运行,所以您需要同步colorList的更新.那么在后台队列上同时执行昂贵的analyzeColors,但是使用串行队列来更新colorList,以确保没有多个更新相互跨越.
>在进行并发处理时,会有收益递减的点.例如,执行复杂的任务并将其分解为2-4个并发循环可能会产生一些性能优势,但如果您开始增加并发线程数太多,您会发现这些线程的开销会对性能产生负面影响.因此,使用不同程度的并发性对此进行基准测试,并且不要认为“更多线程”总是更好.

就如何实现这一点而言,有两种基本技术:

>如果在“并发编程指南:调度队列”指南中看到Performing Loop Iterations Concurrently,他们会讨论dispatch_apply,它是为此目的精确设计的,可以同时运行循环.

colorList = [Int](count: 8,repeatedValue: 0)  // I don't kNow what type this `colorList` array is,so initialize this with whatever type makes sense for your app

let queue = dispatch_get_global_queue(QOS_CLASS_UTILITY,0)

let qos_attr = dispatch_queue_attr_make_with_qos_class(disPATCH_QUEUE_SERIAL,QOS_CLASS_UTILITY,0)
let syncQueue = dispatch_queue_create("com.domain.app.sync",qos_attr)

dispatch_apply(8,queue) { iteration in
    let color = self.photoAnalyzer.analyzeColors(imageStrips[iteration])
    dispatch_sync(syncQueue) {
        colorList[iteration] = color
        return
    }
}

// you can use `colorList` here

请注意,虽然这些迭代并发运行,但整个dispatch_apply循环与您启动它的队列同步运行.这意味着您不希望从主线程调用上面的代码(我们永远不想阻止主线程).所以很可能想把这整件事发送到一些后台队列.

顺便说一下,在WWDC 2011视频Blocks and Grand Central Dispatch in Practice中讨论了dispatch_apply.
>另一种常见模式是创建调度组,使用该组将任务分派到并发队列,并指定dispatch_group_notify以指定完成后要执行的操作.

colorList = [Int](count: 8,so initialize this with whatever type makes sense for your app

let group = dispatch_group_create()
let queue = dispatch_get_global_queue(QOS_CLASS_UTILITY,qos_attr)

for i in 0 ..< 8 {
    dispatch_group_async(group,queue) {
        let color = self.photoAnalyzer.analyzeColors(imageStrips[i])
        dispatch_sync(syncQueue) {
            colorList[i] = color
            return
        }
    }
}

dispatch_group_notify(group,dispatch_get_main_queue()) {
    // use `colorList` here
}

// but not here (because the above code is running asynchronously)

这种方法可以避免完全阻塞主线程,但是必须小心不要添加太多的并发调度任务(因为工作线程是非常有限的资源).

在这两个示例中,我创建了一个专用的串行队列,用于将更新同步到colorList.这可能有点矫枉过正.如果您没有阻塞主队列(无论如何都不应该这样做),您可以将此同步代码分派给主队列(这是一个串行队列).但是为此目的拥有一个专用的串行队列可能更精确.如果这是我将不断与多个线程进行交互的东西,我将使用读写器模式.但这对于这种情况来说可能已经足够了.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐