OC:模拟器iPhoneSE iOS 13;
(60-80秒)
NSTimeInterval t1 = NSDate.date.timeIntervalSince1970;
NSInteger count = 100000;
for (NSInteger i = 0; i < count; i++) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSLog(@"op begin: %ld", i);
self.idx = i;
NSLog(@"op end: %ld", i);
if (i == count - 1) {
NSLog(@"耗时: %f", NSDate.date.timeIntervalSince1970-t1);
}
});
}
Swift:模拟器iPhoneSE iOS 13;
(10-14秒)
let t1 = Date().timeIntervalSince1970
let count = 100000
for i in 0..<count {
DispatchQueue.global().async {
print("subOp begin i:\(i), thred: \(Thread.current)")
self.idx = i
print("subOp end i:\(i), thred: \(Thread.current)")
if i == count-1 {
print("耗时: \(Date().timeIntervalSince1970-t1)")
}
}
}
我以前的工作是使用oc编写代码。最近学会了使用swift。我对通用GCD的广泛性能差距感到惊讶
最佳答案
tl; dr
您很可能正在调试构建。在Swift中,调试版本会进行各种安全检查。如果执行发行版构建,则会关闭这些安全检查,并且性能在很大程度上与Objective-C渲染图没有区别。
一些观察:
index
的交互,它们都不是线程安全的,即您与此属性的交互未同步。如果要从多个线程更新属性,则必须同步访问权限(具有锁,串行队列,读写器并发队列等)。 DISPATCH_QUEUE_PRIORITY_HIGH
,但是您的Swift迭代使用.default
的QoS。我建议使用.userInteractive
或.userInitiated
的QoS来进行比较。 i == count - 1
不足以知道当前所有任务是否都已完成。通常,我们会使用调度组或concurrentPerform
/ dispatch_apply
知道它们何时完成。 concurrentPerform
。在Objective-C中,我们将使用dispatch_apply
。 NSLog
,在Swift中进行print
。那些不是同一回事。如果您想比较效果,建议同时使用NSLog
。 measure
例程,该例程会重复多次。 无论如何,在对所有这些进行校正时,Swift代码的时间在很大程度上与Objective-C的性能没有区别。
这是我使用的例程。在Swift中:
class SwiftExperiment {
// This is not advisable, because it suffers from thread explosion which will exhaust
// the very limited number of worker threads.
func experiment1(completion: @escaping (TimeInterval) -> Void) {
let t1 = Date()
let count = 100_000
let group = DispatchGroup()
for i in 0..<count {
DispatchQueue.global(qos: .userInteractive).async(group: group) {
NSLog("op end: %ld", i);
}
}
group.notify(queue: .main) {
let elapsed = Date().timeIntervalSince(t1)
completion(elapsed)
}
}
// This is safer (though it's a poor use of `concurrentPerform` as there's not enough
// work being done on each thread).
func experiment2(completion: @escaping (TimeInterval) -> Void) {
let t1 = Date()
let count = 100_000
DispatchQueue.global(qos: .userInteractive).async() {
DispatchQueue.concurrentPerform(iterations: count) { i in
NSLog("op end: %ld", i);
}
let elapsed = Date().timeIntervalSince(t1)
completion(elapsed)
}
}
}
以及等效的Objective-C例程:
// This is not advisable, because it suffers from thread explosion which will exhaust
// the very limited number of worker threads.
- (void)experiment1:(void (^ _Nonnull)(NSTimeInterval))block {
NSDate *t1 = [NSDate date];
NSInteger count = 100000;
dispatch_group_t group = dispatch_group_create();
for (NSInteger i = 0; i < count; i++) {
dispatch_group_async(group, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
NSLog(@"op end: %ld", i);
});
}
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSTimeInterval elapsed = [NSDate.date timeIntervalSinceDate:t1];
NSLog(@"耗时: %f", elapsed);
block(elapsed);
});
}
// This is safer (though it's a poor use of `dispatch_apply` as there's not enough
// work being done on each thread).
- (void)experiment2:(void (^ _Nonnull)(NSTimeInterval))block {
NSDate *t1 = [NSDate date];
NSInteger count = 100000;
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^{
dispatch_apply(count, dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0), ^(size_t index) {
NSLog(@"op end: %ld", index);
});
NSTimeInterval elapsed = [NSDate.date timeIntervalSinceDate:t1];
NSLog(@"耗时: %f", elapsed);
block(elapsed);
});
}
我的单元测试:
class MyApp4Tests: XCTestCase {
func testSwiftExperiment1() throws {
let experiment = SwiftExperiment()
measure {
let e = expectation(description: "experiment1")
experiment.experiment1 { elapsed in
e.fulfill()
}
wait(for: [e], timeout: 1000)
}
}
func testSwiftExperiment2() throws {
let experiment = SwiftExperiment()
measure {
let e = expectation(description: "experiment2")
experiment.experiment2 { elapsed in
e.fulfill()
}
wait(for: [e], timeout: 1000)
}
}
func testObjcExperiment1() throws {
let experiment = ObjectiveCExperiment()
measure {
let e = expectation(description: "experiment1")
experiment.experiment1 { elapsed in
e.fulfill()
}
wait(for: [e], timeout: 1000)
}
}
func testObjcExperiment2() throws {
let experiment = ObjectiveCExperiment()
measure {
let e = expectation(description: "experiment2")
experiment.experiment2 { elapsed in
e.fulfill()
}
wait(for: [e], timeout: 1000)
}
}
}
导致
关于ios - 为什么GCD,ObjC和Swift之间的性能差距如此之大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61981363/