当使用 Python 处理一个巨大的 CSV 时突然停止,“杀死”是啥意思?

Posted

技术标签:

【中文标题】当使用 Python 处理一个巨大的 CSV 时突然停止,“杀死”是啥意思?【英文标题】:What does 'killed' mean when a processing of a huge CSV with Python, which suddenly stops?当使用 Python 处理一个巨大的 CSV 时突然停止,“杀死”是什么意思? 【发布时间】:2013-10-11 22:36:10 【问题描述】:

我有一个 Python 脚本,它导入一个大型 CSV 文件,然后计算文件中每个单词的出现次数,然后将计数导出到另一个 CSV 文件。

但是发生的情况是,一旦计数部分完成并开始导出,它会在终端中显示Killed

我不认为这是内存问题(如果是我假设我会遇到内存错误而不是 Killed)。

可能是这个过程花费的时间太长了?如果是这样,有没有办法延长超时时间,这样我就可以避免这种情况?

代码如下:

csv.field_size_limit(sys.maxsize)
    counter=
    with open("/home/alex/Documents/version2/cooccur_list.csv",'rb') as file_name:
        reader=csv.reader(file_name)
        for row in reader:
            if len(row)>1:
                pair=row[0]+' '+row[1]
                if pair in counter:
                    counter[pair]+=1
                else:
                    counter[pair]=1
    print 'finished counting'
    writer = csv.writer(open('/home/alex/Documents/version2/dict.csv', 'wb'))
    for key, value in counter.items():
        writer.writerow([key, value])

Killed 发生在 finished counting 打印之后,完整的消息是:

killed (program exited with code: 137)

【问题讨论】:

发布您收到的错误消息的确切措辞。 "killed" 通常意味着进程收到了一些导致它退出的信号。在这种情况下,由于它与脚本同时发生,因此很有可能它是一个损坏的管道,该进程正在尝试读取或写入另一端已关闭的文件句柄。跨度> 这不是关于 killed 消息来自何处的答案,但如果它是由于超出某种系统内存限制,您可以通过使用 counter.iteritems() 来解决这个问题counter.items() 在你的最后一个循环中。在 Python 2 中,items 返回字典中键和值的列表,如果它非常大,可能需要大量内存。相比之下,iteritems 是一个在任何给定时间只需要少量内存的生成器。 【参考方案1】:

我怀疑有什么东西会因为它需要很长时间而扼杀这个过程。 Killed 通常意味着来自外部的某些东西终止了进程,但在这种情况下可能不会按 Ctrl-C,因为这会导致 Python 在 KeyboardInterrupt 异常上退出。此外,在 Python 中,如果这是问题所在,您会得到 MemoryError 异常。可能发生的情况是您遇到了导致进程崩溃的 Python 或标准库代码中的错误。

【讨论】:

一个崩溃的错误比得到SIGKILL更有可能导致段错误,除非Python出于某种原因在其代码中的某处有raise(SIGKILL) python 中的一个错误不会发送 SIGKILL。【参考方案2】:

退出码 137 (128+9) 表示你的程序由于接收到信号 9 而退出,即SIGKILL。这也解释了killed 消息。问题是,你为什么会收到那个信号?

最可能的原因可能是您的进程超出了允许您使用的系统资源数量的某些限制。根据您的操作系统和配置,这可能意味着您打开的文件过多、使用了过多的文件系统空间或其他原因。最有可能是您的程序使用了太多内存。当内存分配开始失败时,系统不会冒着破坏的风险,而是向使用过多内存的进程发送终止信号。

正如我之前评论的那样,打印finished counting 后可能会达到内存限制的一个原因是,您在最终循环中对counter.items() 的调用分配了一个包含字典中所有键和值的列表。如果你的字典有很多数据,这可能是一个很大的列表。一个可能的解决方案是使用counter.iteritems(),它是一个生成器。它不是返回列表中的所有项目,而是让您以更少的内存使用迭代它们。

所以,我建议你试试这个,作为你的最后一个循环:

for key, value in counter.iteritems():
    writer.writerow([key, value])

请注意,在 Python 3 中,items 返回一个“字典视图”对象,该对象的开销与 Python 2 的版本不同。它取代了iteritems,所以如果你以后升级Python版本,你最终会把循环改回原来的样子。

【讨论】:

正确,但是字典本身也会占用大量内存。 OP 应该考虑以增量方式而不是一次全部读取和处理文件。【参考方案3】:

涉及到两个存储区域:堆栈和堆。堆栈是保存方法调用的当前状态(即局部变量和引用)的地方,而堆是存储对象的地方。 recursion and memory

我猜counter dict 中有太多键会消耗过多的堆区域内存,因此 Python 运行时会引发 OutOfMemory 异常。

为了保存它,不要创建一个巨大的对象,例如计数器

1.***

一个创建太多局部变量的程序。

Python 2.7.9 (default, Mar  1 2015, 12:57:24) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> f = open('stack_overflow.py','w')
>>> f.write('def foo():\n')
>>> for x in xrange(10000000):
...   f.write('\tx%d = %d\n' % (x, x))
... 
>>> f.write('foo()')
>>> f.close()
>>> execfile('stack_overflow.py')
Killed

2.OutOfMemory

创建巨型dict 的程序包含太多键。

>>> f = open('out_of_memory.py','w')
>>> f.write('def foo():\n')
>>> f.write('\tcounter = \n')
>>> for x in xrange(10000000):
...   f.write('counter[%d] = %d\n' % (x, x))
... 
>>> f.write('foo()\n')
>>> f.close()
>>> execfile('out_of_memory.py')
Killed

参考文献

7. Memory : Stack vs Heap recursion and memory

【讨论】:

【参考方案4】:

很可能,您的内存不足,因此内核杀死了您的进程。

你听说过OOM Killer吗?

这是我为处理 CSV 文件中的大量数据而开发的脚本中的日志:

Mar 12 18:20:38 server.com kernel: [63802.396693] Out of memory: Kill process 12216 (python3) score 915 or sacrifice child
Mar 12 18:20:38 server.com kernel: [63802.402542] Killed process 12216 (python3) total-vm:9695784kB, anon-rss:7623168kB, file-rss:4kB, shmem-rss:0kB
Mar 12 18:20:38 server.com kernel: [63803.002121] oom_reaper: reaped process 12216 (python3), now anon-rss:0kB, file-rss:0kB, shmem-rss:0kB

取自/var/log/syslog

基本上:

PID 12216 被选为受害者(由于它使用了 +9Gb 的总虚拟机),因此 oom_killer 获得了它。

这是一篇关于OOM behavior的文章。

【讨论】:

+1,只是为了澄清一下,为了了解我的程序试图使用多少 RAM,我是否应该将这些值加起来:total-vm、anon-rss、file-rss?另外,total-vm 给出了我的程序使用了多少,而不是实际可用内存,对吧?抱歉,知识有限。 我在这方面的知识也有限,@momo。我有点没有时间进行进一步调查,但我发现这篇文章可能会有所帮助:***.com/questions/18845857/…。我可以告诉你的是,total-vm 确实是进程使用的内存量。【参考方案5】:

当我尝试从新的 Ubuntu 20.04 LTS 中 VirtualBox 中的共享文件夹运行 python 脚本时,我也遇到了同样的情况。 Python 在加载我自己的个人库时与Killed 合作。当我将文件夹移动到本地目录时,问题就消失了。似乎Killed 停止发生在我的库的初始导入期间,因为一旦我将文件夹移过来,我就会收到缺少库的消息。

重启电脑后问题就消失了。

因此,如果程序超过某种共享,或者可能只是需要重新启动操作系统的暂时性问题,人们可能想尝试将程序移动到本地目录。

【讨论】:

等等,您必须重新启动主机或虚拟机? 我重新启动了虚拟机。当我构建一个新的虚拟机并且我刚刚安装了 Python 时,这个问题就发生了。重新启动虚拟机后,问题就消失了。我讨厌重新启动作为解决问题的一种方式,所以我花了很多时间尝试调试,经过一个小时的挖掘,我放弃了并做了反弹。

以上是关于当使用 Python 处理一个巨大的 CSV 时突然停止,“杀死”是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 中操作一个巨大的 CSV 文件

Python/SQLAlchemy:如何将巨大的红移表保存到 CSV?

使用 Pandas 在巨大的 CSV 中解析带有嵌套值的 JSON 列

python 处理CSV数据

如何从巨大的 csv 文件中清除不良数据

从巨大的 CSV 文件中读取随机行