是否可以使用多线程加速脚本?
Is it possible to speed up scripts using multi-threading?
我必须使用 DigitalMicrographs 的 DM 脚本语言对数据执行 CPU 深入分析。
我注意到只有一个 CPU 核心在处理过程中达到最大值。有没有办法通过 DM 脚本中的多线程实现更好的性能?简单的例子将不胜感激。
DM 脚本中当然可以使用多线程,F1 帮助中对此进行了说明:
能否实现速度提升取决于多种因素,最重要的是各个线程是否需要访问相同的资源(比如相同的数据,或者某些只能通过主线程访问的 GMS 资源) thread - f.e. UI).
此外,当您对图像表达式使用命令时,很多数据处理在内部已经是多线程的。通过以不需要脚本语言中的 for 循环但使用图像表达式的方式重新表述分析处理,您可能会实现更多的加速。
最后,多线程处理是一种很好的方式,它会引入错误和意外行为,这些错误和意外行为可能真的很难调试。如果您在学习东西时 运行 沉迷于这些东西,请不要感到沮丧。
也就是说,下面的示例演示了(至少在我的机器上)通过在多个并行后台线程上“分块”一些数据分析来提高速度。
// Example showing the explicit use of multi-threading in DM scripting
class CMultiThreadtest
{
image data, keep
number sx,sy,sz
number nChunks, chunksize, lastChunk, doneChunk
object SetData(object self, image img, number nChunks_)
{
if ( img.imagegetNumdimensions() != 3 ) throw( "only 3D data for testing please")
img.ImageGetDimensionSizes(sx,sy,sz)
nChunks = nChunks_
if ( sz % nChunks != 0 ) Throw( "Z-size needs to be integer multiple of nChunks for this test.")
chunksize = sz / nChunks
data:=img
keep = data
return self
}
void CompareResult(object self){
image dif := keep*2-data
number ok = 0==sum(dif)
Result("\n\t Result is " + (ok?"correct":"wrong"))
}
void RunOnData(object self){
// For extra-caution of thread safety, the two lines below shoud be guarded with critical sections
// but given the near-atomic nature of the call, this is omitted here.
number chunkIndex = lastChunk
lastChunk++
image work := data.slice3(0,0,chunkIndex*chunksize, 0,sx,1, 1,sy,1, 2,chunksize,1)
number startp = GetHighresTickCount()
for( number z=0;z<chunksize;z++)
for( number y=0;y<sy;y++ )
for( number x=0;x<sx;x++ ){
work[x,y,z] *= 2
}
number endp = GetHighresTickCount()
Result("\n\t\t Process (chunk "+chunkIndex+") done with " + sx*sy*chunksize + " steps in " + (endp-startp)/GetHighResTicksPerSecond())
// For extra-caution of thread safety, the line below shoud be guarded with critical sections
// but given the near-atomic nature of the call, this is omitted here.
doneChunk++
}
void RunWithSubsets(object self, image src, number nChunks_, number inbackground){
self.SetData(src, nChunks_)
lastChunk = 0
doneChunk = 0
Result("\n.....\n Running with "+nChunks+" chunks of size "+chunksize+ " on " + (inbackground?" multiple background threads":" single main thread") +":")
number startp = GetHighresTickCount()
for( number i=0; i<nChunks; i++){
if ( inbackground )
self.StartThread("runondata")
else
self.RunOnData()
}
while( doneChunk != nChunks ){
if ( ShiftDown() ){
Throw("abort")
doEvents()
}
}
number endp = GetHighresTickCount()
Result("\n Total duration:" + (endp-startp)/GetHighResTicksPerSecond())
self.CompareResult();
Result("\n.....")
}
};
void Test(){
image img := RealImage("test cub",4,50,50,10)
img = random()
clearresults()
object tester = Alloc(CMultiThreadtest)
tester.RunWithSubsets(img, 1, 0)
tester.RunWithSubsets(img, 1, 1)
tester.RunWithSubsets(img, 5, 0)
tester.RunWithSubsets(img, 5, 1)
}
test()
我必须使用 DigitalMicrographs 的 DM 脚本语言对数据执行 CPU 深入分析。 我注意到只有一个 CPU 核心在处理过程中达到最大值。有没有办法通过 DM 脚本中的多线程实现更好的性能?简单的例子将不胜感激。
DM 脚本中当然可以使用多线程,F1 帮助中对此进行了说明:
能否实现速度提升取决于多种因素,最重要的是各个线程是否需要访问相同的资源(比如相同的数据,或者某些只能通过主线程访问的 GMS 资源) thread - f.e. UI).
此外,当您对图像表达式使用命令时,很多数据处理在内部已经是多线程的。通过以不需要脚本语言中的 for 循环但使用图像表达式的方式重新表述分析处理,您可能会实现更多的加速。
最后,多线程处理是一种很好的方式,它会引入错误和意外行为,这些错误和意外行为可能真的很难调试。如果您在学习东西时 运行 沉迷于这些东西,请不要感到沮丧。
也就是说,下面的示例演示了(至少在我的机器上)通过在多个并行后台线程上“分块”一些数据分析来提高速度。
// Example showing the explicit use of multi-threading in DM scripting
class CMultiThreadtest
{
image data, keep
number sx,sy,sz
number nChunks, chunksize, lastChunk, doneChunk
object SetData(object self, image img, number nChunks_)
{
if ( img.imagegetNumdimensions() != 3 ) throw( "only 3D data for testing please")
img.ImageGetDimensionSizes(sx,sy,sz)
nChunks = nChunks_
if ( sz % nChunks != 0 ) Throw( "Z-size needs to be integer multiple of nChunks for this test.")
chunksize = sz / nChunks
data:=img
keep = data
return self
}
void CompareResult(object self){
image dif := keep*2-data
number ok = 0==sum(dif)
Result("\n\t Result is " + (ok?"correct":"wrong"))
}
void RunOnData(object self){
// For extra-caution of thread safety, the two lines below shoud be guarded with critical sections
// but given the near-atomic nature of the call, this is omitted here.
number chunkIndex = lastChunk
lastChunk++
image work := data.slice3(0,0,chunkIndex*chunksize, 0,sx,1, 1,sy,1, 2,chunksize,1)
number startp = GetHighresTickCount()
for( number z=0;z<chunksize;z++)
for( number y=0;y<sy;y++ )
for( number x=0;x<sx;x++ ){
work[x,y,z] *= 2
}
number endp = GetHighresTickCount()
Result("\n\t\t Process (chunk "+chunkIndex+") done with " + sx*sy*chunksize + " steps in " + (endp-startp)/GetHighResTicksPerSecond())
// For extra-caution of thread safety, the line below shoud be guarded with critical sections
// but given the near-atomic nature of the call, this is omitted here.
doneChunk++
}
void RunWithSubsets(object self, image src, number nChunks_, number inbackground){
self.SetData(src, nChunks_)
lastChunk = 0
doneChunk = 0
Result("\n.....\n Running with "+nChunks+" chunks of size "+chunksize+ " on " + (inbackground?" multiple background threads":" single main thread") +":")
number startp = GetHighresTickCount()
for( number i=0; i<nChunks; i++){
if ( inbackground )
self.StartThread("runondata")
else
self.RunOnData()
}
while( doneChunk != nChunks ){
if ( ShiftDown() ){
Throw("abort")
doEvents()
}
}
number endp = GetHighresTickCount()
Result("\n Total duration:" + (endp-startp)/GetHighResTicksPerSecond())
self.CompareResult();
Result("\n.....")
}
};
void Test(){
image img := RealImage("test cub",4,50,50,10)
img = random()
clearresults()
object tester = Alloc(CMultiThreadtest)
tester.RunWithSubsets(img, 1, 0)
tester.RunWithSubsets(img, 1, 1)
tester.RunWithSubsets(img, 5, 0)
tester.RunWithSubsets(img, 5, 1)
}
test()