在Swift中,如何根据某些条件执行并行操作?

5
我需要根据某些条件执行一组操作,例如从数据库中获取数据,每个查询大约需要10秒钟( ConnectedDevices.getAllDetails() 需要10秒才能执行并返回结果)。
这可能与下面的问题类似:在 iPhone 中搜索设备 IP 地址的优化方法 ,但在我的情况下,我需要按批次执行操作,如下面的代码所示:
var isConditionTrue = false
var numProcessed = 0
let dbQueue = dispatch_queue_create("dbQueue", DISPATCH_QUEUE_SERIAL)

// case 1
    for i in 1...10 {

            dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
            let eachDBValue = ConnectedDevices.getAllDetails(i)

                dispatch_async(dbQueue) {
                    if !eachDBValue {
                        numProcessed++
                    }
                }
            }
        }


// case 2
for i in 11...20 {

            dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
            let eachDBValue = ConnectedDevices.getAllDetails(i)

                dispatch_async(dbQueue) {
                    if !eachDBValue {
                        numProcessed++
                    }
                }
            }
        }


// case 3
for i in 21...30 {

            dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
            let eachDBValue = ConnectedDevices.getAllDetails(i)

                dispatch_async(dbQueue) {
                    if !ieachDBValue {
                        numProcessed++
                    }
                }
            }
        }


// case 4
for i in 31...40 {

            dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_UTILITY.value), 0)) {
            let eachDBValue = ConnectedDevices.getAllDetails(i)

                dispatch_async(dbQueue) {
                    if !eachDBValue {
                        numProcessed++
                    }
                }
            }
        }

如果在情况1下,对于1到10的结果为false,则应转到情况2。如果任何实例的结果为true,则不执行任何情况2、3、4。

同样地,对于情况2,如果1到10的结果为false,则应转到情况3,否则应停止。所有这些都需要根据条件来完成。


1
我不明白为什么你要写成 for i in 11...20 而不是 for i in 0...9。对于你代码中的每个 for 循环都有同样的问题。 - Luca Angeletti
1
@appzYourLife - 因为我有这样的情况.. 我需要将循环从0...40分段处理,而不是一次性循环。 - cybergeeeek
当然没有区别,因为 i 没有被使用。 - Luca Angeletti
您正在执行多个 ConnectedDevices.getAllDetails() 的调用。在进行了 n 次调用后,您是否期望得到不同的结果? - Luca Angeletti
@appzYourLife - 我的错误,我忘记了...我们将使用i,并在问题中更新代码。 - cybergeeeek
另一个问题,看着你的代码好像ConnectedDevices.getAllDetails(i)返回一个布尔值。是这样吗? - Luca Angeletti
1个回答

2

这是我的解决方案

虚假的ConnectedDevices类

这是我创建的虚假类,用于测试您的场景。正如您所看到的,getAllDetails方法模拟了您的数据库访问。 它等待10秒钟,只有在输入参数为40时才返回true。这样我们可以在最坏的情况下测试这段代码,因为所有调用都需要完成。

class ConnectedDevices {
    class func getAllDetails(i:Int) -> Bool {
        sleep(10)
        return i == 40
    }
}

Loader 类

这个类将与 Grand Central Dispatch 进行交互。

class Loader {
    private var numProcessed = 0
    private let dbQueue = dispatch_queue_create("dbQueue", DISPATCH_QUEUE_SERIAL)
    private let utilityQueue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)

    func search(completion:(result:Int?)->()) {
        dispatch_async(utilityQueue) {
            for group in [1, 11, 21, 31] {
                if let indexFound = self.search10(group) {
                    completion(result: indexFound)
                    return
                }
            }
            completion(result: nil)
        }
    }

    private func search10(startingIndex:Int) -> Int? {
        var indexFound : Int?
        dispatch_apply(10, utilityQueue) { (delta) -> () in
            let found = ConnectedDevices.getAllDetails(startingIndex + delta)
            dispatch_sync(self.dbQueue) {
                self.numProcessed++ // this is increased anyway
                if found {
                    indexFound = startingIndex + delta
                }
            }
        }
        return indexFound
    }
}

search10(startingIndex:Int)

这个同步方法接收一个 Int 作为参数,并执行 10 个并发调用到 ConnectedDevices.getAllDetails。每个调用都是通过将 startingIndex 加上 deltadelta09)来执行的。

结果被同步放入同步队列中,其中 numProcessed 被安全地增加。如果 foundtrue,则返回“获胜”的索引(startingIndex + delta)。

如果 found 从未变为 true,则返回 nil

search()

这是一个异步方法。它是一个简单的 for loop,其中 group 变量被填充为 1,然后是 11,然后是 21,最后是 31

每次调用 search10。如果它返回一个 Int 值,则将该值传递给 completion 闭包,否则循环继续进行。

如果在没有从 search10 返回值的情况下执行了 4 个循环,则将 nil 传递给 completion 闭包。

Usage

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        debugPrintln("Begin: \(NSDate())")
        Loader().search { (result) -> () in
            debugPrintln(result)
            debugPrintln("End: \(NSDate())")
        }
    }    
}

测试

调用 ConnectedDevices.getAllDetails(...) 40 次需要 40 * 10 = 400 秒

在我的 iPhone 模拟器上,即使没有启用任何优化,这段代码也需要大约 120 秒

希望这是您所需的内容。

P.S.

  1. 请注意,如果当前结果为 true,我也会增加 numProcessed
  2. 我没有找到 isConditionTrue 的目的,所以我已将其移除。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接