将工作分派到多个队列并同步等待

时间:2019-10-26 18:19:43

标签: swift grand-central-dispatch

我希望下面的测试通过。在我的真实代码中,AsyncClass使用DispatchGroup类将工作分配到多个队列。在Swift中,我们使用@escaping完成处理程序来进行异步工作。我正在寻找一种使调用线程等待dispatchGroup完成工作的方法。关闭可能会消失。

长话短说:我有一个调用线程(主线程),该线程正在调用一个将工作分派到多个队列的函数。我希望在进行该工作时阻止调用线程,并在完成工作时取消阻止该线程。结果导致@escapingcompleteHandler可以消失,并且我可以正常地调用函数而无需关闭(并且当我在方法调用后转到下一行时,课程当然就完成了)

我仅将此代码用于测试,我知道我绝不应该在生产中阻塞主线程。

用例:我有一些调用昂贵方法的测试。在此示例中,该方法的工作方式类似于“ AsyncClass”。在AsyncClass内部,我将工作分配给某些线程以加快处理速度。现在,在测试时,我可以一直创建期望,并以闭包形式调用此方法,但这对我来说很冗长。为了方便使用,我想将异步方法转换为同步方法。

import XCTest

class DispatchGroupTestTests: XCTestCase {

    func testIets() {
        let clazz = AsyncClass()

        var isCalled = false

        clazz.doSomething {
            isCalled = true
        }

        XCTAssert(isCalled)
    }

}

class AsyncClass {
    func doSomething(completionHandler: @escaping () -> ()) {
        let dispatchGroup = DispatchGroup()

        for _ in 0...5 {
            dispatchGroup.enter()

            DispatchQueue.global().async {
                let _ = (0...10000).map { $0 * 1000 }

                dispatchGroup.leave()
            }
        }

        dispatchGroup.wait() // Doesn't work

        dispatchGroup.notify(queue: .main) {
            completionHandler()
        }
    }
}

1 个答案:

答案 0 :(得分:0)

我设法做到了这一点(只需在while循环中休眠线程即可):

import XCTest

class DispatchGroupTestTests: XCTestCase {

    func testIets() {
        let clazz = AsyncClass()

        var isCalled = false

        clazz.doSomething {
            isCalled = true
        }

        XCTAssert(isCalled)
    }

}

class AsyncClass {
    func doSomething(completionHandler: () -> ()) {
        var isDone = false
        let dispatchGroup = DispatchGroup()

        for _ in 0...5 {
            dispatchGroup.enter()

            DispatchQueue.global().async {
                let _ = (0...1000000).map { $0 * 10000 }

                dispatchGroup.leave()
            }
        }

        dispatchGroup.notify(queue: .global()) {
            isDone = true
        }

        while !isDone {
            print("sleepy")
            Thread.sleep(forTimeInterval: 0.1)
        }

        completionHandler()
    }
}

现在,不再需要闭包了,期望值可以删除(尽管我在提供的示例中没有期望值,但可以在“真实”测试代码中省略它们):

import XCTest

class DispatchGroupTestTests: XCTestCase {

    var called = false

    func testIets() {
        let clazz = AsyncClass()

        clazz.doSomething(called: &called)

        XCTAssert(called)
    }

}

class AsyncClass {
    func doSomething(called: inout Bool) {
        var isDone = false
        let dispatchGroup = DispatchGroup()

        for _ in 0...5 {
            dispatchGroup.enter()

            DispatchQueue.global().async {
                let _ = (0...1000000).map { $0 * 10000 }

                dispatchGroup.leave()
            }
        }

        dispatchGroup.notify(queue: .global()) {
            isDone = true
        }

        while !isDone {
            print("sleepy")
            Thread.sleep(forTimeInterval: 0.1)
        }

        called = true
    }
}

所以我对度量值块进行了性能测试,并实现了我的期望值(不是XCTestCase期望值):与将所有工作分配给线程相比,将工作分配到其他线程并阻塞自旋锁中的调用线程更快。调用线程(考虑到我们不想转义块,我们希望所有内容都同步,只是为了在测试方法中轻松调用函数)。我只是填写随机计算,结果就是这样:

import XCTest

let work: [() -> ()] = Array.init(repeating: { let _ = (0...1000000).map {  $0 * 213123 / 12323 }}, count: 10)

class DispatchGroupTestTests: XCTestCase {

    func testSync() {
        measure {
            for workToDo in work {
                workToDo()
            }
        }
    }

    func testIets() {
        let clazz = AsyncClass()

        measure {
            clazz.doSomething()
        }
    }

}

class AsyncClass {
    func doSomething() {
        var isDone = false
        let dispatchGroup = DispatchGroup()

        for workToDo in work {
            dispatchGroup.enter()

            DispatchQueue.global().async {
                workToDo()

                dispatchGroup.leave()
            }
        }

        dispatchGroup.notify(queue: .global()) {
            isDone = true
        }

        while !isDone {
            Thread.sleep(forTimeInterval: 0.1)
        }
    }
}

enter image description here