通过删除 numpy 数组来释放内存

2023-12-29

我编写了一个带有 GUI 的疲劳分析程序。该程序获取有限元模型每个元素的单位载荷的应变信息,使用 np.genfromtxt('loadcasefilename.txt') 读取载荷工况,然后进行一些疲劳分析并将每个元素的结果保存在另一个数组中。

负载工况以文本文件形式约为 32Mb,其中有 40 个左右需要循环读取和分析。每个元素的载荷通过载荷工况数组的切片进行插值。

GUI 和疲劳分析在单独的线程中运行。当您单击疲劳分析上的“开始”时,它将开始循环疲劳分析中的载荷工况。

这让我想到了我的问题。如果我有很多元素,分析就无法完成。它多久退出取决于有多少元素,这让我认为这可能是一个内存问题。我尝试通过删除每个循环末尾的负载情况数组(删除所有作为其切片的数组之后)并运行 gc.collect() 来解决此问题,但这没有取得任何成功。

在 MatLab 中,我使用“pack”函数将工作区写入磁盘,清除它,然后在每个循环结束时重新加载它。我知道这不是一个好的做法,但它可以完成工作!我可以用 Python 做同样的事情吗?

代码如下:

for LoadCaseNo in range(len(LoadCases[0]['LoadCaseLoops'])):#range(1):#xxx
    #Get load case data
    self.statustext.emit('Opening current load case file...')
    LoadCaseFilePath=LoadCases[0]['LoadCasePaths'][LoadCaseNo][0]
    #TK: load case paths may be different
    try:
      with open(LoadCaseFilePath):
        pass
    except Exception as e:
        self.statustext.emit(str(e))


    LoadCaseLoops=LoadCases[0]['LoadCaseLoops'][LoadCaseNo,0]
    LoadCase=np.genfromtxt(LoadCaseFilePath,delimiter=',')

    LoadCaseArray=np.array(LoadCases[0]['LoadCaseLoops'])
    LoadCaseArray=LoadCaseArray/np.sum(LoadCaseArray,axis=0)
    #Loop through sections
    for SectionNo in  range(len(Sections)):#range(100):#xxx 
        SectionCount=len(Sections)
        #Get section data
        Elements=Sections[SectionNo]['elements']
        UnitStrains=Sections[SectionNo]['strains'][:,1:]
        Nodes=Sections[SectionNo]['nodes']
        rootdist=Sections[SectionNo]['rootdist']
        #Interpolate load case data at this section
        NeighbourFind=rootdist-np.reshape(LoadCase[0,1:],(1,-1))
        NeighbourFind[NeighbourFind<0]=1e100
        nearest=np.unravel_index(NeighbourFind.argmin(), NeighbourFind.shape)
        nearestcol=int(nearest[1])
        Distance0=LoadCase[0,nearestcol+1]
        Distance1=LoadCase[0,nearestcol+7]
        MxLow=LoadCase[1:,nearestcol+1]
        MxHigh=LoadCase[1:,nearestcol+7]
        MyLow=LoadCase[1:,nearestcol+2]
        MyHigh=LoadCase[1:,nearestcol+8]
        MzLow=LoadCase[1:,nearestcol+3]
        MzHigh=LoadCase[1:,nearestcol+9]
        FxLow=LoadCase[1:,nearestcol+4]
        FxHigh=LoadCase[1:,nearestcol+10]
        FyLow=LoadCase[1:,nearestcol+5]
        FyHigh=LoadCase[1:,nearestcol+11]
        FzLow=LoadCase[1:,nearestcol+6]
        FzHigh=LoadCase[1:,nearestcol+12]
        InterpFactor=(rootdist-Distance0)/(Distance1-Distance0)
        Mx=MxLow+(MxHigh-MxLow)*InterpFactor[0,0]
        My=MyLow+(MyHigh-MyLow)*InterpFactor[0,0]
        Mz=MzLow+(MzHigh-MzLow)*InterpFactor[0,0]
        Fx=-FxLow+(FxHigh-FxLow)*InterpFactor[0,0]
        Fy=-FyLow+(FyHigh-FyLow)*InterpFactor[0,0]
        Fz=FzLow+(FzHigh-FzLow)*InterpFactor[0,0]
        #Loop through section coordinates
        for ElementNo in range(len(Elements)):
            MaterialID=int(Elements[ElementNo,1])
            if Materials[MaterialID]['curvefit'][0,0]!=3:
                StrainHist=UnitStrains[ElementNo,0]*Mx+UnitStrains[ElementNo,1]*My+UnitStrains[ElementNo,2]*Fz

            elif Materials[MaterialID]['curvefit'][0,0]==3:

                StrainHist=UnitStrains[ElementNo,3]*Fx+UnitStrains[ElementNo,4]*Fy+UnitStrains[ElementNo,5]*Mz

            EndIn=len(StrainHist)
            Extrema=np.bitwise_or(np.bitwise_and(StrainHist[1:EndIn-1]<=StrainHist[0:EndIn-2] , StrainHist[1:EndIn-1]<=StrainHist[2:EndIn]),np.bitwise_and(StrainHist[1:EndIn-1]>=StrainHist[0:EndIn-2] , StrainHist[1:EndIn-1]>=StrainHist[2:EndIn]))
            Extrema=np.concatenate((np.array([True]),Extrema,np.array([True])),axis=0)
            Extrema=StrainHist[np.where(Extrema==True)]
            del StrainHist
            #Do fatigue analysis
        self.statustext.emit('Analysing load case '+str(LoadCaseNo+1)+' of '+str(len(LoadCases[0]['LoadCaseLoops']))+' - '+str(((SectionNo+1)*100)/SectionCount)+'% complete')
        del MxLow,MxHigh,MyLow,MyHigh,MzLow,MzHigh,FxLow,FxHigh,FyLow,FyHigh,FzLow,FzHigh,Mx,My,Mz,Fx,Fy,Fz,Distance0,Distance1
    gc.collect()

显然某个地方存在保留周期或其他泄漏,但是如果没有看到您的代码,就不可能说更多。但由于您似乎对解决方法比解决方案更感兴趣......

在 MatLab 中,我使用“pack”函数将工作区写入磁盘,清除它,然后在每个循环结束时重新加载它。我知道这不是一个好的做法,但它可以完成工作!我可以用 Python 做同样的事情吗?

不,Python 没有任何等效项pack。 (当然,如果你确切地知道你想要保留哪一组值,你总是可以np.savetxt or pickle.dump或者以其他方式藏起来,然后exec or spawn一个新的解释器实例,然后np.loadtxt or pickle.load或以其他方式恢复这些值。但是,如果您确切地知道要保留哪一组值,那么您可能一开始就不会遇到此问题,除非您实际上在 NumPy 中遇到了未知的内存泄漏,而这种情况不太可能发生。)


但它有一些东西可能是better。启动一个子进程来分析每个元素(或每批元素,如果它们足够小以至于进程产生的开销很重要),将结果发送回文件或通过队列,然后退出。

例如,如果您这样做:

def analyze(thingy):
    a = build_giant_array(thingy)
    result = process_giant_array(a)
    return result

total = 0
for thingy in thingies:
    total += analyze(thingy)

你可以把它改成这样:

def wrap_analyze(thingy, q):
    q.put(analyze(thingy))

total = 0
for thingy in thingies:
    q = multiprocessing.Queue()
    p = multiprocessing.Process(target=wrap_analyze, args=(thingy, q))
    p.start()
    p.join()
    total += q.get()

(这假设每个thingy and result既小又可腌制。如果它是一个巨大的 NumPy 数组,请查看 NumPy 的共享内存包装器,这些包装器旨在使您需要时变得更容易进程之间直接共享内存 https://docs.python.org/2/library/multiprocessing.html#sharing-state-between-processes而不是通过它。)

但您可能想看看什么multiprocessing.Pool https://docs.python.org/2/library/multiprocessing.html#module-multiprocessing.pool可以为您自动执行此操作(并且更容易扩展代码,例如并行使用所有核心)。请注意,它有一个maxtasksperchild参数,您可以使用该参数每隔 10 个事物回收一次池进程,这样它们就不会耗尽内存。


但回到实际尝试简单地解决问题:

我尝试通过删除每个循环末尾的负载情况数组(删除所有作为其切片的数组之后)并运行 gc.collect() 来解决此问题,但这没有取得任何成功。

这些都不会产生任何影响。如果您只是每次通过循环将所有局部变量重新分配给新值,并且不在其他任何地方保留对它们的引用,那么它们无论如何都会被释放,所以您永远不会拥有超过一次(短暂)2次。和gc.collect()仅当存在引用循环时才有帮助。因此,一方面,这些没有效果是个好消息——这意味着您的代码中没有任何明显愚蠢的内容。另一方面,这是个坏消息——这意味着无论出现什么问题,都并不明显是愚蠢的。

通常人们会看到这一点,因为他们在没有意识到的情况下不断增长一些数据结构。例如,也许你vstack将所有新行移到旧版本上giant_array而不是到一个空数组,然后删除旧版本......但这并不重要,因为每次循环时,giant_array不是 5*N,而是 5*N,然后是 10*N,然后是 15*N,依此类推。 (这只是一个愚蠢的例子I不久前...同样,在对代码一无所知的情况下很难给出更具体的示例。)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过删除 numpy 数组来释放内存 的相关文章

随机推荐

  • 为什么 Fiddler 会破坏我网站的重定向?

    为什么使用 Fiddler 有时会在页面转换时破坏我的网站 服务器端重定向之后 在 http 响应中 如 Fiddler 中所示 我得到以下信息 物体移动 对象转移到了这里 该站点是 ASP NET 1 1 VB NET 1 1 原文如此
  • 为什么使用“数据”和“公式”关键字参数时顺序很重要?

    In R 为什么顺序是data and formula绘图时关键字很重要吗 我以为与命名参数 order isn t应该很重要 有关我的意思的示例 请查看以下代码 library MASS data menarche Correct for
  • Android ADB命令获取设备属性

    我正在尝试从 ADB 命令获取设备属性 我如何通过运行示例 Android 应用程序来获取这些值 我多么希望使用 adb shell 命令本身来让我的生活更轻松 这是我完成示例应用程序的方法 但我想要相应的 adb 命令 设备制造商 设备硬
  • Android 模拟器中的应用程序错误问题“出现网络错误”

    添加平台 android 后 我在 android 上运行 ionic 应用程序 我通过它运行 ionic emulate android l c 我不明白为什么会这样 它的 android 清单文件是
  • 如何使用 Windows Phone 8 连接到已托管在服务器上的 SQL Server 数据库

    由于我在 Windows Phone 8 开发方面不太熟练 我想讨论 询问将我的 Windows Phone 8 连接到 SQL Server 数据库的最佳方法是什么 我不想使用 Azure 因为我已经有了数据库存在于用于网站的服务器上 请
  • 在 C# 中将时间转换为格式化字符串

    Time ToString 0 0 显示为十进制 1 5 而不是 1 30 如何让它以时间格式显示 private void xTripSeventyMilesRadioButton CheckedChanged object sender
  • 无法通过 tor ConnectionRefusedError 发出 python 请求:[WinError 10061]

    我试图通过 tor 使用 python 请求发出请求 但收到错误 ConnectionRefusedError WinError 10061 无法建立连接 因为目标计算机主动拒绝它 这是我正在使用的代码 import requests de
  • 长 iPhone 应用程序名称将显示在多行中

    我的应用程序名称长度为 17 个字符 当安装在设备上时 它看起来像应用程序 名称 有没有办法在多行上显示应用程序名称 请帮忙 不 你不能 我认为 iPad 支持 15 个字符来完整显示应用程序名称 iPhone 支持 14 个字符 iPho
  • Matplotlib:光标捕捉到带有日期时间轴的绘制数据

    我有一个由 3 个数据集组成的图 其中 x 轴上有日期时间对象 我想要一个可以捕捉数据并显示精确的 x 和 y 值的光标 我已经有一个 捕捉光标 但这只适用于标量 x 轴 谁能帮我修改捕捉光标 使其也适用于日期时间 x 轴 Here are
  • 计算appwidget的高度

    我无法通过谷歌搜索这个问题找出或找到解决方案 我有一个带有 appwidget 的 Android 应用程序 看起来像http www livescorewidget eu img screendumps widget png http w
  • 具有外部域注册商的 Route 53?

    我创建了一个 Route 53 托管区域 其中包含 SOA NS 记录和 A 记录 A 记录指向我在 AWS 上托管的 Web 实例 在注册商上 我需要使用什么才能让域使用 Amazon Route 53 仅仅是名称服务器吗 或者我需要 A
  • 创建事件是否是将 XF OnAppearing 变成异步方法的有效方法?

    我最近看到了关于如何将应用程序 OnStart 变成异步 OnStart 的建议 protected override void OnStart this started onStarted Subscribe to event start
  • 创建配置节处理程序时出错

    我有一个 dot NET 4 0 Web 应用程序 定义了自定义部分
  • 具有单行 TabPanel 和溢出面板的 TabControl

    我想将 WPF TabControl 的功能更改为仅生成一行 并为每个其他项目 如 ToolBar ToolBarOverflowPanel 创建一个溢出弹出窗口 目前 VisualStudio 中选项卡的显示方式相同 这就是我得到的
  • Swift 3 GCD 锁定变量和 block_and_release 错误

    我正在使用 Swift 3 GCD 来在我的代码中执行一些操作 但我越来越 dispatch call block and release经常出错 我想这个错误背后的原因是因为不同的线程修改相同的变量 但我不知道如何解决问题 这是我的代码和
  • 从参数化测试访问夹具(例如,capsys)

    我在参数化测试中访问固定装置 在本例中为 capsys 时遇到问题 目前我正在使用一个虚拟夹具来完成这项工作 import pytest pytest fixture def params request from collections
  • 如何在 Swift 中从文件(而不是整个文件)读取数据块

    假设我有一个 8 字节长的文件 仅包含 ASCII 字符 brownfox 我不想加载 2 个字节的块 而不是加载整个文件并处理 if UInt8 并对 2 字节大小的块进行操作 因此操作如下 load br从文件 和not整个文件 对数据
  • 云代码函数运行两次

    我写了一个运行良好的云函数 有时 同一用户会多次执行此函数 我确保客户端 Android 应用程序只请求一个请求 经过一些调试后 我注意到如果连接不良就会出现此问题 我可能是正确的 也可能不正确 如何克服这样的问题 正如评论中所述 我也不相
  • 如何使用 php 在数据库中插入和检索图像

    我正在尝试上传会员个人资料的图像并使用 php 将其存储在数据库中 然后检索它 但它对我不起作用 这就是我尝试插入图像的方法
  • 通过删除 numpy 数组来释放内存

    我编写了一个带有 GUI 的疲劳分析程序 该程序获取有限元模型每个元素的单位载荷的应变信息 使用 np genfromtxt loadcasefilename txt 读取载荷工况 然后进行一些疲劳分析并将每个元素的结果保存在另一个数组中