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

我有一个 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)
174912 次浏览

我怀疑任何事情都会扼杀这个过程,只是因为它需要很长的时间。Kled 通常意味着某些来自外部的东西终止了进程,但是在这种情况下可能不会触发 Ctrl-C,因为这会导致 Python 在 KeyboardInterrupt 异常上退出。另外,在 Python 中,如果出现这种问题,就会得到 MemoryError 异常。可能发生的情况是,您在 Python 或标准库代码中遇到了 bug,从而导致进程崩溃。

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

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

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

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

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

注意,在 Python3中,items返回一个“ dictionary view”对象,它的开销与 Python2的版本不同。它取代了 iteritems,所以如果您稍后升级 Python 版本,您最终将把循环修改回原来的样子。

涉及到两个存储区域: 堆栈和堆。堆栈是保存方法调用当前状态的地方(即本地变量和引用) ,堆是存储对象的地方。递归和内存

我认为在 counter dict 中有太多的键会占用堆区域的太多内存,因此 Python 运行时将引发 内存耗尽异常。

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

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、内存不足

一个程序创建一个巨大的 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

参考文献

最有可能的情况是,您耗尽了内存,所以内核终止了您的进程。

你听说过 OOM 杀手吗?

下面是我为处理来自 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 的 total-vm) ,所以 哦,杀手收获了它。

这是一篇关于 OOM 行为的文章。

当我试图在新的 Ubuntu 20.04 LTS 中从 VirtualBox的共享文件夹运行一个 python 脚本时,同样的事情发生在我身上。Python 在加载我自己的个人库时使用 Killed退出。当我将文件夹移动到本地目录时,问题就消失了。看来,Killed停止发生在我的库的初始导入期间,因为我得到了消息,一旦我移动文件夹丢失库。

我重新启动电脑后,这个问题就消失了。

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