2010-01-29 3 views
2

Мне было интересно, имеет ли Python аналогичные проблемы, такие как C, относительно порядка выполнения определенных элементов кода.Порядок выполнения Python

Например, я знаю, что в C временами говорят, что не гарантируется, что какая-то переменная инициализируется перед другой. Или только потому, что одна строка кода выше другой, не гарантируется, что она реализована перед всеми ниже нее.

Это то же самое для Python? Например, если я открываю файл данных, читаю данные, закрываю файл, а затем делаю другие вещи, я точно знаю, что файл закрыт до того, как строки после закрытия файла будут выполнены ??

Причина, по которой я спрашиваю, заключается в том, что я пытаюсь прочитать в большом файле данных (1,6 ГБ) и использовать этот модуль python для работы, которую я делаю на данных. Когда я запускаю этот модуль я получаю сообщение об ошибке:

File "/glast01/software/ScienceTools/ScienceTools-v9r15p2-SL4/sane/v3r18p1/python/GtApp.py", line 57, in run 
    input, output = self.runWithOutput(print_command) 
    File "/glast01/software/ScienceTools/ScienceTools-v9r15p2-SL4/sane/v3r18p1/python/GtApp.py", line 77, in runWithOutput 
    return os.popen4(self.command(print_command)) 
    File "/Home/eud/jmcohen/.local/lib/python2.5/os.py", line 690, in popen4 
    stdout, stdin = popen2.popen4(cmd, bufsize) 
    File "/Home/eud/jmcohen/.local/lib/python2.5/popen2.py", line 199, in popen4 
    inst = Popen4(cmd, bufsize) 
    File "/Home/eud/jmcohen/.local/lib/python2.5/popen2.py", line 125, in __init__ 
    self.pid = os.fork() 
OSError: [Errno 12] Cannot allocate memory 
>>> 
Exception exceptions.AttributeError: AttributeError("Popen4 instance has no attribute 'pid'",) in <bound method Popen4.__del__ of <popen2.Popen4 instance at 0x9ee6fac>> ignored 

я предполагаю, что это связано с размером данных, которую я прочитал в (она имеет 17608310 строки и 22 столбцов). Я подумал, что, возможно, если бы я закрыл файл, который я открыл сразу после того, как прочитал данные, это поможет, но это не так. Это заставило меня задуматься о порядке выполнения строк кода, следовательно, о моем вопросе.

Благодаря

+8

Думаю, вам нужно объяснить себя лучше. В C задано 'f(); g(); ',' f() 'гарантированно оценивается до' g() '. В 'a = f() + g();' порядок оценки не указан в C. Python гарантирует оценку слева направо: http://docs.python.org/reference/expressions.html#evaluation- заказывайте –

+2

«вопросами», вы имеете в виду «правила», не так ли? – KevinDTimm

+0

Да, я знал, что не очень хорошо себя объясняю, извините, это связано с тем, что он не полностью понимает все это, но пытается тоже :) Алок: Да, это то, о чем я думал. Я думал, что это также переносится на вещи, например, когда файл может закрыться. Я знаю, что могу сказать, что определить две разные функции и назвать вторую (по второму, я имею в виду только нижнюю часть кода) от первого, так что в этом смысле тоже не обязательно делается по порядку. kevindtimm: Да, я имел в виду правила.Думаю, я просто использовал проблемы с работой, потому что это дало мне проблемы :) – Jamie

ответ

3

Исполнение C, безусловно, является последовательным, для фактических утверждений. Существуют даже правила, которые определяют sequence points, поэтому вы можете знать, как оценивают отдельные выражения.

2

CPython сам написан таким образом, что любые эффекты, подобные тем, которые вы упоминаете, минимизированы; код всегда выполняется сверху вниз за исключением буквального оценки во время компиляции, объекты GCed как только их RefCount хиты 0 и т.д.

10

Единственное, что я могу думать о том, что может удивить некоторых людей является:

def test(): 
    try: 
     return True 
    finally: 
     return False 

print test() 

Выход:

False 

finally положение действительно выполняется в прошлом, даже если return заявление предшествует им. Однако это не относится к Python.

1

«Если я открываю файл данных, читаю данные, закрываю файл, то делаю другие вещи, я точно знаю, что файл закрыт до того, как строки после того, как я закрою файл?»

Закрытый да.

Дата выхода из памяти. Нет. Никаких гарантий о том, когда произойдет сбор мусора.

Кроме того, при закрытии файла ничего не говорится обо всех других созданных вами переменных, а остальные объекты, которые вы оставили, привязаны к этим переменным.

Нет проблемы с «порядком операций».

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

0

Если данные состоят из столбцов и строк, почему бы не использовать встроенный итератор файлов для извлечения одной строки за раз?

f = open('file.txt') 
first_line = f.next() 
2

Выполнение в cpython vm очень линейно. Я не думаю, что у вас есть какая-то проблема с порядком исполнения.

В Python вы должны быть осторожны, но не C: исключения могут быть подняты повсюду, поэтому только потому, что вы видите вызов close() под соответствующим вызовом open(), это не означает, что вызов действительно достигнут. Используйте try/finally всюду (или инструкцию with на достаточно новых питонах), чтобы убедиться, что открытые файлы закрыты (и освобождены явные освобождения от других видов ресурсов).

Если ваша проблема связана с использованием памяти, а не с каким-либо другим ресурсом, отладка может быть сложнее. Память не может быть явно освобождена в python. Cpython vm (который, скорее всего, вы используете), освобождает память, как только последняя ссылка на нее уходит, но иногда не может освободить память, захваченную циклами, с объектами, которые имеют метод __del__. Если у вас есть какие-либо методы __del__ или используйте их, это может быть частью вашей проблемы.

Ваш реальный вопрос (память, а не порядок исполнения) трудно ответить, не видя больше кода. Это может быть что-то очевидное (или, по крайней мере, может быть какой-то очевидный способ уменьшить объем требуемой памяти).

0

popen2.py:

class Popen4(Popen3): 
    childerr = None 

    def __init__(self, cmd, bufsize=-1): 
     _cleanup() 
     self.cmd = cmd 
     p2cread, p2cwrite = os.pipe() 
     c2pread, c2pwrite = os.pipe() 
     self.pid = os.fork() 
     if self.pid == 0: 
      # Child 
      os.dup2(p2cread, 0) 
      os.dup2(c2pwrite, 1) 
      os.dup2(c2pwrite, 2) 
      self._run_child(cmd) 
     os.close(p2cread) 
     self.tochild = os.fdopen(p2cwrite, 'w', bufsize) 
     os.close(c2pwrite) 
     self.fromchild = os.fdopen(c2pread, 'r', bufsize) 

man 2 fork:

Функция вилка() может потерпеть неудачу, если:

[ENOMEM]
              Недостаточно места для хранения.

os.popen4 в конечном итоге вызывает open2.Popen4.__init__, которые должны fork для того, чтобы создать дочерний процесс, который вы пытаетесь читать/писать. Этот базовый вызов терпит неудачу, вероятно, из-за исчерпания ресурсов.

Возможно, вы используете слишком много памяти в другом месте, в результате чего fork попытается использовать больше, чем ограничение RLIMIT_DATA или RLIMIT_RSS, предоставленное вашему пользователю. Как рекомендовано Python memory profiler - Stack Overflow, Heapy может помочь вам определить, так ли это.

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