是否可以使用多线程加速脚本?

Posted

技术标签:

【中文标题】是否可以使用多线程加速脚本?【英文标题】:Is it possible to speed up scripts using multi-threading? 【发布时间】:2022-01-16 22:06:21 【问题描述】:

我必须使用 DigitalMicrographs 的 DM 脚本语言对数据执行 CPU 密集型分析。 我注意到在处理过程中只有一个 CPU 内核达到最大值。有没有办法通过 DM 脚本中的多线程来获得更好的性能?简单的例子将不胜感激。

【问题讨论】:

第一个谷歌结果看起来很有希望,不是吗?做你的研究。 (我不太了解这个话题,所以我不会在这里投反对票):***.com/questions/25500016/… @Zabuzard 不,我不认为这是重复的。这是特定于速度改进的,在我所知道的 DM 脚本中几乎没有这样的例子。实际上,我现在正在回答这个问题...... 公平。但是链接的答案显示了如何使用线程,不是吗?基本上回答“如何在 DM 脚本中使用多线程”。 @Zabuzard:当然,但问题实际上是“是否可以加速脚本”,而不是是否可以有多个线程。这确实是一个更复杂的问题。 【参考方案1】:

在 DM 脚本中当然可以使用多线程,它在此处的 F1 帮助中有记录:

能否实现速度提升取决于多种因素,最重要的是各个线程是否需要访问相同的资源(例如相同的数据,或者某些只能通过主线程获得的 GMS 资源 - fe 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()

【讨论】:

非常感谢,正是我想要的。

以上是关于是否可以使用多线程加速脚本?的主要内容,如果未能解决你的问题,请参考以下文章

在 Python 脚本中同时使用多处理和多线程来加快执行速度

多线程可以加速内存分配吗?

python循环怎么用多线程去运行

加速总结循环的多线程 C++ 程序

为啥使用多线程更新数组没有加速

mongodb 单事务内使用多线程加速的简单例子