Уведомления

Группа в Telegram: @pythonsu

#1 Ноя. 13, 2010 20:18:28

Игнат
От:
Зарегистрирован: 2010-10-02
Сообщения: 224
Репутация: +  0  -
Профиль   Отправить e-mail  

обработка исключений

питон 3.1

есть класс. он содержит куеуе:

self.queue = queue.Queue()
каждый поток запускается с worker=threadMain:

def threadMain(self):

import queue

while True:
try:
target = self.queue.get_nowait()
except queue.Empty:
return 0
Мне непонятно значение queue.Empty
Логично предположить, что при некоторых раскладах queue.get_nowait() не возвращает ничего и соответственно возбуждается исключение queue.Empty

но во-первых - просветите пожалуйста, когда оно обычно возбуждается? когда закончатся данные, занесенные эту очередь через queue.put()?

во-вторых, что меня сбивает с толку, если убрать обработку исключения и оставить просто target = queue.get_nowait() — все нормально работает.



Отредактировано (Ноя. 13, 2010 20:34:02)

Офлайн

#2 Ноя. 14, 2010 06:50:27

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

обработка исключений

Прекратите издеваться.
Очередь пустая - будет исключение.
У вас, наверное, такое не происходит - вот и прокатывает.

Уберите import queue из функции. Импорт внутри потока возможен, но иногда бьет по рукам - есть пара ньюансов.



Офлайн

#3 Ноя. 14, 2010 10:20:43

Игнат
От:
Зарегистрирован: 2010-10-02
Сообщения: 224
Репутация: +  0  -
Профиль   Отправить e-mail  

обработка исключений

не было и в мыслях над кем-нибудь издеваться
если бы я понимал как это работает и знал отличия 2.6 от 3.1, вполне вероятно что мне хватило бы и гугла

>>Так ищите raise Empty
вот основная проблема!

0. except Empty:
NameError: global name ‘Empty’ is not defined

1.
self.queue = queue.Queue()
except self.queue.Empty:

AttributeError: ‘Queue’ object has no attribute ‘Empty’

2 except queue.Empty:
NameError: global name ‘queue’ is not defined


3 except Queue.Empty:
NameError: global name ‘Queue’ is not defined

объясните пожалуйста, к чему обращаться? к глобальному имени queue, к его экземпляру self.queue = queue.Queue(), и почему у них обоих нет атрибута Empty?

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



Офлайн

#4 Ноя. 14, 2010 11:07:14

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

обработка исключений

Издевались те, кто пытался вам отвечать.

Исключение не в классе Queue а в модуле queue.
Делать как-то так:

import queue
import time

class A(object):
def __init__(self):
self.queue = queue.Queue()

def put(self, val):
self.queue.put(val)

def process(self):
while True:
try:
val = self.queue.get_nowait()
# process val
except queue.Empty:
time.sleep(1) # just for example
Кусок из queue.py. Если неблокирующий запрос и очередь пустая - будет исключение.
    def get(self, block=True, timeout=None):
"""Remove and return an item from the queue.

If optional args 'block' is true and 'timeout' is None (the default),
block if necessary until an item is available. If 'timeout' is
a positive number, it blocks at most 'timeout' seconds and raises
the Empty exception if no item was available within that time.
Otherwise ('block' is false), return an item if one is immediately
available, else raise the Empty exception ('timeout' is ignored
in that case).
"""
self.not_empty.acquire()
try:
if not block:
if not self._qsize():
raise Empty
elif timeout is None:
while not self._qsize():
self.not_empty.wait()
elif timeout < 0:
raise ValueError("'timeout' must be a positive number")
else:
endtime = _time() + timeout
while not self._qsize():
remaining = endtime - _time()
if remaining <= 0.0:
raise Empty
self.not_empty.wait(remaining)
item = self._get()
self.not_full.notify()
return item
finally:
self.not_empty.release()

def get_nowait(self):
"""Remove and return an item from the queue without blocking.

Only get an item if one is immediately available. Otherwise
raise the Empty exception.
"""
return self.get(False)
Отличия между 2.6 и 3.1 в данном случае свелись к переименованию модуля, чтобы он назывался с маленькой буквы - и все.



Офлайн

#5 Ноя. 14, 2010 11:21:02

Игнат
От:
Зарегистрирован: 2010-10-02
Сообщения: 224
Репутация: +  0  -
Профиль   Отправить e-mail  

обработка исключений

спасибо за подробный ответ
ошибка была в том, что import queue стоял в начале конструктора, а не в начале файла.

но всё же -

        while True:
try:
acc = self.queue.get_nowait()
except queue.Empty:
print('empty!')
return 0
- все потоки выдают исключение и соответственно завершают свою работу

acc = self.queue.get_nowait()
- все нормально работает.

почему так?



Офлайн

#6 Ноя. 14, 2010 11:34:29

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

обработка исключений

Уверены, что потоки таки работают?
Я бы скорее предположил (всего кода не вижу, поэтому догадываюсь), что ваши потоки попросту тихо умирают по этому самому queue.Empty, никому об этом не говоря.



Офлайн

#7 Ноя. 14, 2010 12:11:57

Игнат
От:
Зарегистрирован: 2010-10-02
Сообщения: 224
Репутация: +  0  -
Профиль   Отправить e-mail  

обработка исключений

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



Офлайн

#8 Ноя. 14, 2010 12:40:09

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

обработка исключений

сеанс гадания закончен. Больше ничего по вашим шести строчкам сказать не могу.



Офлайн

#9 Ноя. 14, 2010 12:48:39

Игнат
От:
Зарегистрирован: 2010-10-02
Сообщения: 224
Репутация: +  0  -
Профиль   Отправить e-mail  

обработка исключений

вот полный код
все незначительные методы гуи опущены, функция check() - это основная задача потока, она работает нормально. изначально она была сделана для однопоточной версии, там тем более все в порядке

проверку исключения закомментировал, сразу за ней идет получение задачи из queue без проверок

import sys
import sip
from PyQt4 import QtCore, QtGui
from ui import Ui_Form
import queue

from lib import check

class run(QtGui.QMainWindow):

def __init__(self, parent=None):

QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.queue = queue.Queue()

# connectors
###
QtCore.QObject.connect(self.ui.button_start,
QtCore.SIGNAL("clicked()"),
self.start)

def unique(self): #
def load(self): #
def clear(self): #
def setLabelTotal(self, num): #
def labelValidInc(self): #
def labelInvalidInc(self): #
def labelTotalDec(self): #

def start(self):
import threading

''' check accounts mt '''
accs = self.ui.text_accs.toPlainText().splitlines()

for acc in accs:
self.queue.put(acc)

for test in range(len(accs)):
new_thread = threading.Thread(target=self.threadMain)
new_thread.start()

threading.Thread.join(new_thread)

def threadMain(self):
''' thread body '''
global app

## while True:
## try:
## acc = self.queue.get_nowait()
## except queue.Empty:
## print('empty!')
## return 0

acc = self.queue.get_nowait() # work

res = check(acc) # thread body (not included)

newAccsText = self.ui.text_accs.toPlainText().replace(acc, '')

if res == 1:
self.ui.text_accs_valid.appendPlainText(acc)
self.labelValidInc()
else:
self.labelInvalidInc()

self.ui.text_accs.setPlainText(newAccsText.strip())
self.labelTotalDec()
app.processEvents() # update gui

##################################################################

if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myApp = run()
myApp.show()

sys.exit(app.exec_())



Офлайн

#10 Ноя. 14, 2010 14:05:52

Андрей Светлов
От:
Зарегистрирован: 2007-05-15
Сообщения: 3137
Репутация: +  14  -
Профиль   Адрес электронной почты  

обработка исключений

Ошибка была в threadMain - уберите while и будет вам счастье. Но недолго.

Без ножа режете - так с потоками обращаться. Не нужно делать их столько.
Есть такое понятие - thread pool. Как раз для подобных задачек придумано.

import sys
import sip
from PyQt4 import QtCore, QtGui
from ui import Ui_Form
#import queue
#import threading

# install from http://pypi.python.org/pypi/futures
# doc in http://www.python.org/dev/peps/pep-3148/
from concurency.futures import ThreadPoolExecutor

from lib import check

class run(QtGui.QMainWindow):

def __init__(self, parent=None):

QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
self.executor = ThreadPoolExecutor(max_workers=5) # should be relative small
self.pending = set()
self.queue = queue.Queue()

# connectors
###
QtCore.QObject.connect(self.ui.button_start,
QtCore.SIGNAL("clicked()"),
self.start)

def closeEvent(self, event):
event.accept()
for p in self.pendings:
p.cancel()
self.executor.shutdown() # wait for processing all pending tasks

def unique(self): pass#
def load(self): pass#
def clear(self): pass#
def setLabelTotal(self, num): pass#
def labelValidInc(self): pass#
def labelInvalidInc(self): pass#
def labelTotalDec(self): pass#

def start(self):

''' check accounts mt '''
accs = self.ui.text_accs.toPlainText().splitlines()

for acc in accs:
future = self.executor.submit(self.worker, acc)
self.pending.add(future)
future.add_done_callback(self.process_result)

def process_result(self, future):
# callback is called in main thread
# it's good practice to communicate with UI in main thread only

self.pending.discard(future)

if future.cancelled():
# cancelled on shutdown
return

acc, res = future.result()
newAccsText = self.ui.text_accs.toPlainText().replace(acc, '')

if res == 1:
self.ui.text_accs_valid.appendPlainText(acc)
self.labelValidInc()
else:
self.labelInvalidInc()

self.ui.text_accs.setPlainText(newAccsText.strip())
self.labelTotalDec()


def worker(self, acc):
# worker precesses own code in one of executor threads
res = check(acc) # thread body (not included)
return acc, res


##################################################################

if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myApp = run()
myApp.show()

sys.exit(app.exec_())



Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version