在不移除线程锁的情况下优化代码
Optimize code without removing thread lock
我正在尝试在一个已经很忙的应用程序上进行纹波模拟。现在,cpu 运行s 在最低处理器上大约为 11 毫秒。到目前为止,其中的所有代码 运行 都在主线程上。
我希望可以将纹波模拟完全放在另一个线程上。
模拟是基于苹果GLCameraRipple project。基本上它创建了一个镶嵌矩形,并计算纹理坐标。所以在理想的世界中,纹理坐标和波纹模拟数组都将在不同的线程上。
我现在使用的更新函数如下所示。它确实在某种程度上利用了 GCD,但是由于同步,这样做并没有提高速度。如果没有同步,应用程序将会崩溃,因为 swift 数组不是线程安全的。
var rippleTexCoords:[GLfloat] = []
var rippleSource:[GLfloat] = []
var rippleDest:[GLfloat] = []
func runSimulation()
{
if (firstUpdate)
{firstUpdate = false; Whirl.crashLog("First update")}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let block1: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */ This will actually run at the end
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let me:Int = (y + 1) * (pw + 2) + x + 1
let a = self.rippleSource[ai]
let b = self.rippleSource[bi]
let c = self.rippleSource[ci]
let d = self.rippleSource[di]
var result = self.rippleDest[me]
result = (a + b + c + d) / 2.0 - result
result -= result / 32.0
self.rippleDest[me] = result
}
//Defer goes here
}
dispatch_apply(Int(poolHeighti), queue, block1);
/*for y in 0..<poolHeighti {
block1(y: y)
}*/
let hm1 = GLfloat(poolHeight - 1)
let wm1 = GLfloat(poolWidth - 1)
let block2: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */
let yy = GLfloat(y)
let pw = self.poolWidthi
for x in 1..<(pw - 1) {
let xx = GLfloat(x)
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let a = self.rippleDest[ai]
let b = self.rippleDest[bi]
let c = self.rippleDest[ci]
let d = self.rippleDest[di]
var s_offset = ((b - a) / 2048)
var t_offset = ((c - d) / 2048)
s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
s_offset = (s_offset > 0.5) ? 0.5 : s_offset;
t_offset = (t_offset > 0.5) ? 0.5 : t_offset;
let s_tc = yy / hm1
let t_tc = xx / wm1
let me = (y * pw + x) * 2
self.rippleTexCoords[me + 0] = s_tc + s_offset
self.rippleTexCoords[me + 1] = t_tc + t_offset
}
}
dispatch_apply(poolHeighti, queue, block2)
/* for y in 0..<poolHeighti {
block2(y: y)
} *///
let pTmp = rippleDest
rippleDest = rippleSource
rippleSource = pTmp
}
有什么方法可以强制此代码在不同的线程上不断 运行 吗?或者以某种方式让它运行得更快?
我不知道这是否可能,但如果可能的话,我会在以下线程中使用这些数组:
主要:
- 波纹顶点
- 波纹指数
次要:(这些从不在主线程上读取或写入)
- 纹波来源
- rippleDest
在两个线程上:
- rippleTexCoords(在主线程上读取,在辅助线程上写入)
如果满足这些条件,那么 运行 模拟方法可能 运行 在第二个线程上没有问题。
obj_sync 阻止您的代码在多个线程上 运行,因此 dispatch_apply 只会减慢速度。
现在内存非常便宜。为什么不将结果保存在额外的工作数组中?对 rippleDest 和 rippleSource 的只读访问不需要同步。你只需要在将计算结果复制到 rippleDest 时使用锁,从而将cing 锁定时间减少到最低限度。
对于其他速度增益,我首先将所有索引 ai、bi、ci、di、me 的初始化移出循环,因为它们在每次迭代中仅递增 1 .即使在编译器优化之后,这也会为每个节点节省至少六次操作——这是与过程完成的有用工作一样多的操作。你可能不会从中得到 50% 的改善,但接近 10-15%,这还不错。
我正在尝试在一个已经很忙的应用程序上进行纹波模拟。现在,cpu 运行s 在最低处理器上大约为 11 毫秒。到目前为止,其中的所有代码 运行 都在主线程上。
我希望可以将纹波模拟完全放在另一个线程上。
模拟是基于苹果GLCameraRipple project。基本上它创建了一个镶嵌矩形,并计算纹理坐标。所以在理想的世界中,纹理坐标和波纹模拟数组都将在不同的线程上。
我现在使用的更新函数如下所示。它确实在某种程度上利用了 GCD,但是由于同步,这样做并没有提高速度。如果没有同步,应用程序将会崩溃,因为 swift 数组不是线程安全的。
var rippleTexCoords:[GLfloat] = []
var rippleSource:[GLfloat] = []
var rippleDest:[GLfloat] = []
func runSimulation()
{
if (firstUpdate)
{firstUpdate = false; Whirl.crashLog("First update")}
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
let block1: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */ This will actually run at the end
let pw = self.poolWidthi
for x in 1..<(pw - 1)
{
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let me:Int = (y + 1) * (pw + 2) + x + 1
let a = self.rippleSource[ai]
let b = self.rippleSource[bi]
let c = self.rippleSource[ci]
let d = self.rippleSource[di]
var result = self.rippleDest[me]
result = (a + b + c + d) / 2.0 - result
result -= result / 32.0
self.rippleDest[me] = result
}
//Defer goes here
}
dispatch_apply(Int(poolHeighti), queue, block1);
/*for y in 0..<poolHeighti {
block1(y: y)
}*/
let hm1 = GLfloat(poolHeight - 1)
let wm1 = GLfloat(poolWidth - 1)
let block2: (y: size_t) -> Void = {
(y: size_t) -> Void in
objc_sync_enter(self)
defer { objc_sync_exit(self) } // */
let yy = GLfloat(y)
let pw = self.poolWidthi
for x in 1..<(pw - 1) {
let xx = GLfloat(x)
let ai:Int = (y ) * (pw + 2) + x + 1
let bi:Int = (y + 2) * (pw + 2) + x + 1
let ci:Int = (y + 1) * (pw + 2) + x
let di:Int = (y + 1) * (pw + 2) + x + 2
let a = self.rippleDest[ai]
let b = self.rippleDest[bi]
let c = self.rippleDest[ci]
let d = self.rippleDest[di]
var s_offset = ((b - a) / 2048)
var t_offset = ((c - d) / 2048)
s_offset = (s_offset < -0.5) ? -0.5 : s_offset;
t_offset = (t_offset < -0.5) ? -0.5 : t_offset;
s_offset = (s_offset > 0.5) ? 0.5 : s_offset;
t_offset = (t_offset > 0.5) ? 0.5 : t_offset;
let s_tc = yy / hm1
let t_tc = xx / wm1
let me = (y * pw + x) * 2
self.rippleTexCoords[me + 0] = s_tc + s_offset
self.rippleTexCoords[me + 1] = t_tc + t_offset
}
}
dispatch_apply(poolHeighti, queue, block2)
/* for y in 0..<poolHeighti {
block2(y: y)
} *///
let pTmp = rippleDest
rippleDest = rippleSource
rippleSource = pTmp
}
有什么方法可以强制此代码在不同的线程上不断 运行 吗?或者以某种方式让它运行得更快?
我不知道这是否可能,但如果可能的话,我会在以下线程中使用这些数组:
主要:
- 波纹顶点
- 波纹指数
次要:(这些从不在主线程上读取或写入)
- 纹波来源
- rippleDest
在两个线程上:
- rippleTexCoords(在主线程上读取,在辅助线程上写入)
如果满足这些条件,那么 运行 模拟方法可能 运行 在第二个线程上没有问题。
obj_sync 阻止您的代码在多个线程上 运行,因此 dispatch_apply 只会减慢速度。
现在内存非常便宜。为什么不将结果保存在额外的工作数组中?对 rippleDest 和 rippleSource 的只读访问不需要同步。你只需要在将计算结果复制到 rippleDest 时使用锁,从而将cing 锁定时间减少到最低限度。
对于其他速度增益,我首先将所有索引 ai、bi、ci、di、me 的初始化移出循环,因为它们在每次迭代中仅递增 1 .即使在编译器优化之后,这也会为每个节点节省至少六次操作——这是与过程完成的有用工作一样多的操作。你可能不会从中得到 50% 的改善,但接近 10-15%,这还不错。