2016-02-19 3 views
0

Я новичок в Python, и сейчас я работаю над решением проблем, чтобы улучшить свои навыки кодирования. В настоящее время я работаю над вопросом, где мне нужно было ввести stable sort и ввести значения, скорректированные на обратное. Я запрограммировал его и выполнил код в онлайн-судье веб-сайта и для одного тестового примера (не знаю теста), я получил ошибку Memory Limit Exceeded. Поэтому после некоторых исследований я понял, что в коде есть memory leak, и код не полностью эффективен. Поэтому я установил memory_profiler python для мониторинга потребления памяти процесса, а также поэтапного анализа потребления памяти моего кода.Идентификация утечки памяти в python - Профайлер памяти

Ниже приведены данные ввода, кода, вывода и анализа профилей памяти, взятые из memory_profiler.

Вход:

8 
1 2 
16 3 
11 2 
20 3 
3 5 
26 4 
7 1 
22 4 

Код:

from collections import OrderedDict 
@profile 
def test_1(): 
    print "Enter the number: " 
    n = raw_input() 
    k = [] 
    v = [] 
    print "Enter ID and M: " 
    for i in range(0,int(n)): 
     a, b = raw_input().split(' ') 
     k.append(a) 
     v.append(b) 
    d = OrderedDict(zip(k,v)) 
    sorted_items = sorted(d.items(), key=lambda (k,v):int(v), reverse=True) 
    for i, j in sorted_items: 
     print i, j 

if __name__ == '__main__': 
     test_1() 

Выход:

Line # Mem usage Increment Line Contents 
================================================ 
    2 10.520 MiB 0.000 MiB @profile 
    3        def test_1(): 
    4 10.531 MiB 0.012 MiB  print "Enter the number: " 
    5 10.551 MiB 0.020 MiB  n = raw_input() 
    6 10.551 MiB 0.000 MiB  k = [] 
    7 10.551 MiB 0.000 MiB  v = [] 
    8 10.551 MiB 0.000 MiB  print "Enter ID and M: " 
    9 10.551 MiB 0.000 MiB  for i in range(0,int(n)): 
    10 10.551 MiB 0.000 MiB    a, b = raw_input().split(' ') 
    11 10.551 MiB 0.000 MiB    k.append(a) 
    12 10.551 MiB 0.000 MiB    v.append(b) 
    13 
    14 10.551 MiB 0.000 MiB  d = OrderedDict(zip(k,v)) 
    15 10.555 MiB 0.004 MiB  sorted_items = sorted(d.items(), key=lambda (k,v):int(v), reverse=True) 
    16 10.555 MiB 0.000 MiB  for i, j in sorted_items: 
    17 10.555 MiB 0.000 MiB    print i, j 

Ожидаемый результат (я в состоянии получить желаемый результат):

3 5 
26 4 
22 4 
16 3 
20 3 
1 2 
11 2 
7 1 

Является ли этот код неэффективным для более высоких входных или более высоких номеров? из анализа я мог видеть, что используется только меньше памяти, но для этого конкретного тестового примера я мог видеть, что использование памяти составляет более 16 МБ. Может кто-нибудь сказать мне, где я делаю неправильно. Является ли мой подход неправильным или поток неправильный? Не могли бы вы рассказать мне, почему я не могу получить результат, как ожидалось. Заранее спасибо. Любая помощь приветствуется.

+0

Каков ожидаемый выход? И почему вы думаете, что он должен использовать меньше памяти? – gil

+0

обновил вопрос, чтобы отобразить ожидаемый результат – Dev

+0

Похоже, что ваш код верен, как и моя пересмотренная версия. Поскольку нет способа узнать тестовый пример (человек, который разработал этот онлайн-курс, должен действительно переосмыслить это), давайте просто посмотрим, поможет ли очистка списков и изменение 'range' на' xrange'. – gil

ответ

1

Я писал комментарий, но он становился слишком длинным, поэтому я думаю, что я мог бы обновить его до ответа.

Прежде всего, декоратор profile использует довольно немного памяти только сам по себе. Как вы можете видеть:

from memory_profiler import profile 
@profile 
def foo(): 
    pass 

и я получаю

Line # Mem usage Increment Line Contents 
================================================ 
    2  28.5 MiB  0.0 MiB @profile 
    3        def foo(): 
    4  28.5 MiB  0.0 MiB  pass 

Ваш номер не будет, вероятно, меняться (я бегу на Python 3, в IDE не меньше), но это в основном то же самое с вашей функции , Почти все использование памяти исходит от линии @profile (10.520 MiB), и то, что добавлено вашей функцией (см. Колонку «Приращение»), тривиально (0,36 MiB).

Результат состоит в том, что у вас не должно быть проблем с его внешностью (если то, что вы разместили, - это уже весь ваш код, и я полагаю, что это так). Я не знаю, какой тест может дать вам Memory Limit Exceeded. Нам действительно нужно знать, что это за тест, чтобы исследовать проблему.

Тем не менее, одно улучшение может сделать ваш код более эффективным, особенно для большого количества входов. Вам не нужно создавать промежуточные списки (k и v в вашем коде).Написать в Словаре сразу:

d = OrderedDict() 
for i in range(int(n)): # Note you don't need range(0, x); just range(x) 
    a, b = raw_input().split() # No need for an argument to split, either 
    d[a] = b 

Даже лучше, вы можете избежать for цикла и использовать более эффективную экспрессию генератора:

d = OrderedDict(raw_input().split() for _ in range(int(n))) 

Выражение генератор представляет собой выражение вида (foo something_like_a_for_loop) (формальное описание here); окружающие круглые скобки могут быть опущены, если это единственный аргумент функции. Это похоже на список по-разному: вы можете перебирать его с помощью for, вы можете получить список из него с помощью list, вы можете использовать его всякий раз, когда ожидается итератор. Но это занимает намного меньше места, чем эквивалентный список, когда список длинный. (Но есть и отличие: а выражение гена может повторяться через только один раз, не может быть проиндексирована и не имеет len и т.д. Вы можете прочитать больше об этом here.)

Есть другие малые улучшения, которые вы можете сделать. Все включенные в переписку ниже

def test_1(): 
    n = int(raw_input('Enter the number: ')) 
    d = OrderedDict(raw_input().split() for _ in range(n)) 
    sorted_items = sorted(d.items(), key=lambda k_v: int(k_v[1]), reverse=True) 
    for i, j in sorted_items: 
     print i, j 
+0

спасибо, что объяснили я и помогаю мне дать мне более эффективное решение. Я пойму это и узнаю. Я действительно не знаю, что это за тест, так как это онлайн-судья, который проверяет код со своими собственными тестовыми примерами. но я позволю попробовать с этим решением и посмотреть, к чему это приводит. – Dev

+0

и это полное решение, которое я предоставил – Dev

+1

@Dev Другое дело, так как вы на python 2: используйте 'xrange 'вместо' range'. 'range' создает весь список сразу и может быть огромным:' xrange' (который становится просто 'range' в python 3) возвращает одно значение за раз и занимает незначительную память: https://docs.python.org/2/library/functions.html#xrange – gil

Смежные вопросы