'Bị giết' có nghĩa là gì khi quá trình xử lý một CSV lớn với Python, đột ngột dừng lại?


89

Tôi có một tập lệnh Python nhập một tệp CSV lớn và sau đó đếm số lần xuất hiện của mỗi từ trong tệp, sau đó xuất số lượng sang một tệp CSV khác.

Nhưng điều đang xảy ra là khi phần đếm đó kết thúc và quá trình xuất bắt đầu, nó sẽ hiển thị Killedtrong thiết bị đầu cuối.

Tôi không nghĩ đây là vấn đề về bộ nhớ (nếu có, tôi cho rằng tôi sẽ gặp phải lỗi bộ nhớ nhưng không phải Killed).

Có thể là quá trình này mất quá nhiều thời gian? Nếu vậy, có cách nào để kéo dài thời gian chờ đợi để tôi có thể tránh được điều này?

Đây là mã:

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])

Và điều Killedxảy ra sau khi finished countingđã được in, và thông báo đầy đủ là:

killed (program exited with code: 137)

6
Đăng từ ngữ chính xác của thông báo lỗi bạn đang nhận được.
Robert Harvey

2
"bị giết" thường có nghĩa là quá trình nhận được một số tín hiệu khiến nó thoát ra. Trong trường hợp này vì nó xảy ra cùng lúc với script nên rất có thể đó là một đường ống bị hỏng, quá trình đang cố gắng đọc từ hoặc ghi vào một tệp điều khiển đã được đóng ở đầu kia.
Andrew Clark

3
Đó không phải là câu trả lời về việc killedthông báo đến từ đâu, nhưng nếu đó là do vượt quá giới hạn bộ nhớ hệ thống nào đó, bạn có thể khắc phục điều đó bằng cách sử dụng counter.iteritems()thay vì counter.items()trong vòng lặp cuối cùng của mình. Trong Python 2, itemstrả về danh sách các khóa và giá trị trong từ điển, có thể yêu cầu nhiều bộ nhớ nếu nó rất lớn. Ngược lại, iteritemslà một máy phát điện chỉ yêu cầu một lượng nhỏ bộ nhớ tại bất kỳ thời điểm nào.
Blckknght

Câu trả lời:


101

Mã thoát 137 (128 + 9) cho biết rằng chương trình của bạn đã thoát do nhận được tín hiệu 9, nghĩa là SIGKILL. Điều này cũng giải thích killedthông điệp. Câu hỏi đặt ra là tại sao bạn lại nhận được tín hiệu đó?

Lý do rất có thể là do quy trình của bạn đã vượt qua một số giới hạn về số lượng tài nguyên hệ thống mà bạn được phép sử dụng. Tùy thuộc vào hệ điều hành và cấu hình của bạn, điều này có thể có nghĩa là bạn có quá nhiều tệp đang mở, sử dụng quá nhiều dung lượng mục tệp hoặc thứ gì khác. Rất có thể là chương trình của bạn đã sử dụng quá nhiều bộ nhớ. Thay vì mạo hiểm mọi thứ bị hỏng khi việc cấp phát bộ nhớ bắt đầu không thành công, hệ thống đã gửi một tín hiệu kết thúc quá trình đang sử dụng quá nhiều bộ nhớ.

Như tôi đã nhận xét trước đó, một lý do khiến bạn có thể đạt giới hạn bộ nhớ sau khi in finished countinglà lệnh gọi đến counter.items()trong vòng lặp cuối cùng của bạn phân bổ một danh sách chứa tất cả các khóa và giá trị từ từ điển của bạn. Nếu từ điển của bạn có nhiều dữ liệu, đây có thể là một danh sách rất lớn. Một giải pháp khả thi sẽ là sử dụng counter.iteritems()máy phát điện. Thay vì trả lại tất cả các mục trong một danh sách, nó cho phép bạn lặp lại chúng với mức sử dụng bộ nhớ ít hơn nhiều.

Vì vậy, tôi khuyên bạn nên thử điều này, như là vòng lặp cuối cùng của bạn:

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

Lưu ý rằng trong Python 3, itemstrả về đối tượng "dạng xem từ điển" không có chi phí tương tự như phiên bản của Python 2. Nó thay thế iteritems, vì vậy nếu sau này bạn nâng cấp các phiên bản Python, bạn sẽ kết thúc việc thay đổi vòng lặp trở lại như cũ.


2
Đúng, nhưng bản thân từ điển cũng sẽ chiếm rất nhiều bộ nhớ. OP nên xem xét việc đọc và xử lý tệp tăng dần thay vì tất cả cùng một lúc.
Kevin

24

Có hai vùng lưu trữ liên quan: ngăn xếp và ngăn xếp. Ngăn xếp là nơi lưu giữ trạng thái hiện tại của một lệnh gọi phương thức (tức là các biến cục bộ và tham chiếu) và heap là nơi các đối tượng được lưu trữ. đệ quy và bộ nhớ

Tôi cho rằng có quá nhiều khóa trong counterdict sẽ chiếm quá nhiều bộ nhớ của vùng heap, vì vậy thời gian chạy Python sẽ tạo ra một ngoại lệ OutOfMemory .

Để lưu nó, đừng tạo một đối tượng khổng lồ, ví dụ như bộ đếm .

1.StackOverflow

một chương trình tạo quá nhiều biến cục bộ.

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

một chương trình tạo ra một người khổng lồ dictbao gồm quá nhiều chìa khóa.

>>> 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

Người giới thiệu

2

Tôi nghi ngờ bất cứ điều gì đang giết chết quá trình chỉ vì nó mất nhiều thời gian. Nói chung, bị giết có nghĩa là thứ gì đó từ bên ngoài đã chấm dứt quá trình, nhưng có lẽ không phải trong trường hợp này, nhấn Ctrl-C vì điều đó sẽ khiến Python thoát khỏi ngoại lệ KeyboardInterrupt. Ngoài ra, trong Python, bạn sẽ nhận được ngoại lệ MemoryError nếu đó là vấn đề. Những gì có thể đang xảy ra là bạn đang gặp lỗi trong Python hoặc mã thư viện tiêu chuẩn gây ra sự cố quy trình.


Một lỗi bị treo sẽ có nhiều khả năng dẫn đến mặc định hơn là nhận được SIGKILL, trừ khi Python có một raise(SIGKILL)nơi nào đó trong mã của nó vì lý do nào đó.
Kevin

1
Lỗi trong python sẽ không gửi SIGKILL.
qwr

2

Rất có thể, bạn đã hết bộ nhớ, vì vậy Kernel đã giết quá trình của bạn.

Bạn đã nghe về OOM Killer chưa?

Đây là nhật ký từ một tập lệnh mà tôi đã phát triển để xử lý một bộ dữ liệu khổng lồ từ các tệp 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

Nó được lấy từ /var/log/syslog.

Về cơ bản:

PID 12216 được bầu làm nạn nhân (do nó sử dụng + 9Gb tổng vm), vì vậy oom_killer đã gặt hái nó.

Đây là một bài viết về hành vi OOM .


1
+1, chỉ để làm rõ, để hiểu chương trình của tôi đang cố gắng sử dụng bao nhiêu RAM, tôi có nên cộng các giá trị total-vm, anon-rss, file-rss không? Ngoài ra và total-vm cho biết chương trình của tôi đang sử dụng bao nhiêu chứ không phải bộ nhớ có sẵn thực tế, phải không? Xin lỗi, kiến ​​thức có hạn.
momo

1
Kiến thức của tôi cũng hạn chế về bối cảnh này, @momo. Tôi không còn thời gian để điều tra thêm, nhưng tôi thấy bài đăng này có thể hữu ích: stackoverflow.com/questions/18845857/… . Những gì tôi có thể nói với bạn, đó là thực sự, tổng vm, là dung lượng bộ nhớ được sử dụng bởi quá trình.
ivanleoncz

0

Tôi vừa gặp phải trường hợp tương tự khi cố chạy một tập lệnh python từ một thư mục được chia sẻ trong VirtualBoxUbuntu 20.04 LTS mới. Python đã được bảo vệ Killedkhi tải thư viện cá nhân của riêng tôi. Khi tôi di chuyển thư mục đến một thư mục cục bộ, sự cố đã biến mất. Có vẻ như việc Killeddừng đã xảy ra trong lần nhập thư viện đầu tiên của tôi vì tôi nhận được thông báo thiếu thư viện sau khi tôi chuyển thư mục qua.

Sự cố đã biến mất sau khi tôi khởi động lại máy tính của mình.

Do đó, mọi người có thể muốn thử di chuyển chương trình đến một thư mục cục bộ nếu nó nằm trên một phần của một số loại hoặc nó có thể là một sự cố thoáng qua chỉ cần khởi động lại hệ điều hành.


Chờ đã, bạn phải khởi động lại máy chủ của mình hay máy ảo?
cglacet

Đúng. Trong trường hợp của tôi, tôi đang xây dựng một máy ảo mới và tôi vừa cài đặt Python khi gặp sự cố này. Sau khi khởi động lại, nó biến mất. Tôi ghét khởi động lại như một cách để sửa chữa mọi thứ vì vậy tôi đã dành rất nhiều thời gian để cố gắng gỡ lỗi và sau một giờ đào, kể cả ở đây trong SO. Nhưng cuối cùng, tôi đã từ bỏ và khởi động lại và bắt đầu. Tôi không biết tại sao nó hoạt động.
Timothy C. Quinn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.