Порядок исполнения Python - PullRequest
       9

Порядок исполнения Python

4 голосов
/ 29 января 2010

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

Например, я знаю, что в 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 столбца).Я подумал, что, может быть, если я закрою файл, который открыл сразу после прочтения данных, это поможет, но это не помогло.Это заставило меня задуматься о порядке выполнения строк кода, отсюда и мой вопрос.

Спасибо

Ответы [ 7 ]

11 голосов
/ 29 января 2010

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

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

print test()

Выход:

False
Предложения

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

3 голосов
/ 29 января 2010

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

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

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

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

3 голосов
/ 29 января 2010

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

3 голосов
/ 29 января 2010

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

1 голос
/ 29 января 2010

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

Закрыто да.

Выпущено из памяти. Нет. Никаких гарантий относительно того, когда будет происходить сборка мусора.

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

Там нет вопроса "порядок операций".

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

0 голосов
/ 29 января 2010

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)

человек 2 вилка :

Функция fork () может завершиться ошибкой, если:

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

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

Возможно, вы используете слишком много памяти в другом месте, из-за чего fork пытается использовать больше, чем RLIMIT_DATA или RLIMIT_RSS, данное вашему пользователю. В соответствии с рекомендациями Профилировщик памяти Python - Переполнение стека , Heapy может помочь определить, так ли это.

0 голосов
/ 29 января 2010

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

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