当前位置: 首页 > 面试题库 >

使用GCD并行处理阵列

孔鸿哲
2023-03-14
问题内容

我有一个很大的数组,我想通过将它的片段交给一些异步任务来处理。作为概念证明,我编写了以下代码:

class TestParallelArrayProcessing {
    let array: [Int]
    var summary: [Int]

    init() {
        array = Array<Int>(count: 500000, repeatedValue: 0)
        for i in 0 ..< 500000 {
            array[i] = Int(arc4random_uniform(10))
        }
        summary = Array<Int>(count: 10, repeatedValue: 0)
    }

    func calcSummary() {
        let group = dispatch_group_create()
        let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)

        for i in 0 ..< 10 {
            dispatch_group_async(group, queue, {
                let base = i * 50000
                for x in base ..< base + 50000 {
                    self.summary[i] += self.array[x]
                }
            })
        }
        dispatch_group_notify(group, queue, {
            println(self.summary)
        })
    }
}

之后init()array将使用0到9之间的随机整数初始化。

calcSummary函数array使用它们各自的插槽summary作为累加器,分派10个任务,这些任务从50000个项目的不相交的块中将它们相加并相加。

程序self.summary[i] += self.array[x]在行崩溃。错误是:

 EXC_BAD_INSTRUCTION (code = EXC_I386_INVOP).

我可以看到,在调试器中,它在崩溃前已经进行了几次迭代,并且在崩溃时变量具有正确范围内的值。

我读过EXC_I386_INVOP尝试访问已发布的对象时可能发生的情况。我想知道这是否与Swift修改数组是否有关系,如果是的话,如何避免它。


问题答案:

这与@Eduardo的答案中使用Array类型withUnsafeMutableBufferPointer<R>(body: (inout UnsafeMutableBufferPointer<T>) -> R) -> R方法的方法稍有不同。该方法的文档指出:

Call body(p),其中p是指向Array的可变连续存储的指针。如果不存在这样的存储,则会首先创建它。

通常,优化程序可以消除数组算法中的边界检查和唯一性检查,但是当失败时,在body的参数上调用相同的算法可以让您以安全为代价。

第二段似乎正是这里发生的情况,因此在Swift中使用此方法可能更“惯用”,无论是什么意思:

func calcSummary() {
    let group = dispatch_group_create()
    let queue = dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)

    self.summary.withUnsafeMutableBufferPointer {
        summaryMem -> Void in
        for i in 0 ..< 10 {
            dispatch_group_async(group, queue, {
                let base = i * 50000
                for x in base ..< base + 50000 {
                    summaryMem[i] += self.array[x]
                }
            })
        }
    }

    dispatch_group_notify(group, queue, {
        println(self.summary)
    })
}


 类似资料:
  • 我正在编写一个需要处理大量URL的java程序 每个URL将按顺序运行以下作业:下载、分析、压缩 我希望每个作业都有固定数量的线程,这样所有作业在任何给定时间都有并发运行的线程,而不是每个URL一次使用一个线程来完成所有作业。 例如,下载作业将有多个线程来获取和下载URL,一旦其中一个URL被下载,它就会将其传递给分析作业中的一个线程,一旦完成,它就会传递给压缩作业中的一个线程,等等。 我正在考虑

  • 我正在处理大量的4K图像,通过在图像的小(64x64像素)补丁上计算一个参数。这项任务现在是按顺序进行的,一个补丁一个补丁。下面复制了一段我的代码来向您展示这个想法。 结果: 顺序:15754毫秒 并行:5899 ms

  • 我的Spring批处理作业每3分钟运行一次。 步骤应为 每个用户的记录应该并行执行。每个用户最多可以有150k条记录。 每个用户都可以有更新和删除记录。更新记录应在删除之前运行。 更新/删除集应该自己并行运行。但严格来说,所有更新都应该在删除之前完成。 有谁能提出在多个级别实现并行性的最佳方法,并遵循更新和删除级别的顺序吗。我正在研究Spring异步执行器服务、并行流和其他Spring库。Rx,仅

  • 我正在使用在每一行上执行一个函数,这需要很长时间,为了加快速度,有没有一种方法可以使用并行处理,使多个核心在不同的行上并发工作? 例如,我将PRISM天气数据(https://prism.oregonstate.edu/)聚合到州一级,同时按人口加权。这是基于https://www.patrickbaylis.com/blog/2021-08-15-pop-weighted-weather/. 请

  • 当我使用Spring批处理管理运行长时间运行的批处理作业的多个实例时,它会在达到jobLauncher线程池任务执行程序池大小后阻止其他作业运行。但是从cron中提取多个工作似乎效果不错。下面是作业启动器配置。 Spring批处理管理员Restful API是否使用不同于xml配置中指定的作业启动器?

  • 使用Camel拆分数组列表,并在多达10个线程中并行处理每个项目。以下是配置。线程池配置文件被设置为最大线程数=10。 bean:reportRepository?method=getPendingTransactions获取ArrayList并传递给Splitter。 是处理项目的处理器。 问题:当作业开始时,它正在启动10个线程,但是一些线程正在拾取同一个项目。例如,如果我在数组列表中有ite