2013-01-15 2 views
3

У меня в настоящее время проблема с моим скриптом Python, когда я выполняю функцию SQL из cursor.execute() для определенной функции, она выполняет функцию, завершает работу и то скрипт зависает где-то около пяти часов, прежде чем возобновить оставшуюся часть программы.Python зависает во время cursor.execute() с помощью Psycopg2

Я смотрю статус сервера своей функции в pgAdminIII, так как он вызывается из Python, и когда функция завершается, сервер просто показывает открытое соединение с моим пользователем python. Прежде чем он будет работать в транзакции, но после добавления conn.set_isolation_level (0), он показывает только открытое соединение.

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

Сложность состоит в том, что обе стороны продолжают указывать на другую как на источник проблемы. Я предполагаю, что это какой-то эффект взаимодействия от этой конкретной функции. Возможно, сигнал не отправляется обратно на python из postgres после запуска конкретной функции? Ни одна из других функций не имеет проблемы с одним и тем же способом выполнения.

Идеи? Решения? -Я рассматривал таймаут, но время работы может варьироваться от 20 минут до 2 часов. - Функция, которую он запускает, создает таблицу и возвращает только строку с надписью «Завершить», все операции учитываются в базе данных после ее исчезновения в качестве активной функции в статусе сервера.

Вот код, я использую для репликации проблемы, выделенной из моего основного сценария:

#!/usr/bin/env python 

import sys 
import os 
import smtplib 
import ftplib 
import gzip 
import logging 
import shutil 
import argparse 
import traceback 
import subprocess 
from email.mime.text import MIMEText 

import psycopg2 
import psycopg2.extras 
import psycopg2.extensions 
from psycopg2 import OperationalError 

pg_db = "ppl" 
pg_port = "5432" 
pg_user = "<user>" 
pg_pass = "<pass>" 
pg_host = "<host>" 

# connect to database 
try: 
    conn = psycopg2.connect(database=pg_db, 
          port=pg_port, 
          user=pg_user, 
          password=pg_pass, 
          host=pg_host) 
    conn.set_isolation_level(0) 
except: 
    print "Unable to connect to the database." 

cur = conn.cursor() 

print 'Starting select <function1>' 
cur.execute("select <function1>(999999, null);") 
print 'Assign variable...' 
a = cur.fetchall() 
print 'Done' 

print 'Starting select <function2>' 
cur.execute("select <function2>(999999, null);") 
print 'Assign variable...' 
b = cur.fetchall() 
print 'Done' 

print a 
print b 

conn.close() 
sys.exit() 

Тогда я побежал Трассирование как предложено с этими результатами:

<previous function statements for about 4k lines> 

write(1, "Starting select <function>"..., 45) = 45 
sendto(3, "Q\0\0\0009select <function>"..., 58, MSG_NOSIGNAL, NULL, 0) = 58 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "T\0\0\0001\0\1<function_name>\0"..., 16384, 0, NULL, NULL) = 500 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0mSINFO\0C00000\0Mv_eval_table "..., 16384, 0, NULL, NULL) = 110 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\4\247SINFO\0C00000\0Mcmd := CREATE"..., 16384, 0, NULL, NULL) = 1192 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\23hSINFO\0C00000\0Mcmd := \t--For"..., 16384, 0, NULL, NULL) = 4969 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 672 
... 
brk(0xbe9000)       = 0xbe9000 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 168 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 1008 
... 

<does this for about 600k more lines before executing the rest of the script, I am assuming it is indefinitely looping until a timeout> 

Далее я побежал cProfile для функции, которая завернула второй блок кода, который назвал вторую функцию:

Tue Jan 15 16:04:50 2013 function2_prof 

     7 function calls in 15755.988 CPU seconds 

    Random listing order was used 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.000 0.000 0.000 0.000 {method 'cursor' of 'psycopg2._psycopg.connection' objects} 
     1 0.000 0.000 15755.988 15755.988 test_sql_sub2.py:48(LR2) 
     1 15755.988 15755.988 15755.988 15755.988 {method 'execute' of 'psycopg2._psycopg.cursor' objects} 
     1 0.000 0.000 15755.988 15755.988 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.000 0.000 0.000 0.000 {method 'close' of 'psycopg2._psycopg.cursor' objects} 
     1 0.000 0.000 0.000 0.000 {method 'fetchall' of 'psycopg2._psycopg.cursor' objects} 
+0

Пробовал создавать отдельные курсоры для каждого вызова функции, все еще не увенчались успехом. – BagoDev

+0

, поскольку он возобновляет (в конечном итоге), а не вешает навсегда, вы можете попробовать обнюхивать трафик, привязать strace к python и т. Д. И посмотреть, что на самом деле происходит за эти пять часов – Eevee

+0

несколько рекомендаций: вы действительно должны включать информацию о версии в свой вопрос (ОС, Postgresql, Python и т. Д.); Люди обычно просят об этом. Затем вы должны дать определения функций. Наконец, я попробую назвать вашу функцию параметрами. это просто хорошая идея. Я не уверен, что это поможет, но я надеюсь на это. –

ответ

0

вопрос был связан с одной строкой в ​​нескольких для петель в функции SQL:

raise info 'license_row_id := %', rec.license_row_id; 

Они поднимают информационные сообщения были каким-то образом не обрабатываются должным образом на питона, как они были на Баш и pgAdmin. Я предполагаю, что из-за того, что они были необработаны, они продолжали цикл и обработку и требовали большего объема памяти, пока он не смог обработать, наконец, сбросив информацию о повышении без предупреждения или ошибки и возобновления программы.

Я прокомментировал эту ненужную информационную строку, и весь скрипт заработал через 20 минут, нормальное время выполнения программы. Если у кого-то есть идея, как заставить python обрабатывать информационные сообщения из postgresql, которые, вероятно, еще больше ответят на эту проблему.

+0

отредактировал мой ответ, хотя здесь мало что можно сделать – Eevee

1

Я думаю, что ваша функция делает больше, чем вы понимаете. Посмотрите на свое Трассировании:

brk(0xbe9000)       = 0xbe9000 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 84 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 168 
poll([{fd=3, events=POLLIN|POLLERR}], 1, -1) = 1 ([{fd=3, revents=POLLIN}]) 
recvfrom(3, "N\0\0\0SSINFO\0C00000\0Mlicense_row_i"..., 16384, 0, NULL, NULL) = 1008 

brk означает «дать мне больше памяти», так ясно Python накапливает данные. poll проверяет наличие данных; положительное возвращаемое значение (здесь, 1) есть. И recvfrom считывает эти данные и возвращает количество прочитанных байтов.

Похоже, Postgres посылает вам много данных, столько, сколько требуется для получения. Я не очень разбираюсь в формате проводки Postgres, но в каждом опросе наверняка звучит так, будто вы возвращаете тонны и тонны строк. Функция больше не отображается как исполняемая, так как она не; работа выполнена, и Postgres теперь просто отправляет результаты назад.

Неудивительно, что обе стороны обвиняют другую; проблема в середине. :)


редактировать: Aha, больше информации подразумевает RAISE INFO.Psycopg2 действительно хранит все эти уведомления, on the connection object.

Это только сохраняет последние пятьдесят, но если вы отправляете более полумиллиона замечает клиент, это займет некоторое время, чтобы превратить их в строки Python, выбрасывая старую, добавив новейшим и т. д. Если клиент командной строки полностью игнорирует их (или даже делает это все на C), это, естественно, будет намного быстрее.

Таким образом, простое решение - «не делай этого». :) Вы также можете configure Postgres not to send these to the client, но, конечно же, они будут бесполезны для отладки. Нет никакого способа, который я могу видеть, чтобы попросить psycopg2 не собирать уведомления, отправленные клиенту.

+0

Хорошо, это проблема, единственная функция, которую возвращает функция, - это одна строка с одной строкой, которая говорит «Завершить». Я также запускаю это вручную на pgAdminIII и от Bash, и они занимают примерно 20 минут. Я не могу предоставить функцию, но могу сказать, что она в основном создает таблицу из разных таблиц в разных схемах, а затем заканчивается, передавая имя вновь созданной таблицы. Так что, если он не возвращает тонны и тонны строк, что он может отправить обратно на python? Это дает больше, чем просто возвращение? – BagoDev

+0

, не видя функции, я понятия не имею. но вы должны иметь некоторые результаты в 'a' и' b'; распечатать их и посмотреть, что они собой представляют. – Eevee

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