Уведомления

Группа в Telegram: @pythonsu
  • Начало
  • » GUI
  • » Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага? [RSS Feed]

#1 Март 16, 2010 09:47:36

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага?

Очень прошу помочь.

Написал программу, которая прекрасно работала в одном потоке. Но после добавления рабочих потоков, время от времени стали выскакивать чудесные баги. Много часов провел за отладкой, расставил кучу принтов и…. получил такую штуку - время от времени сигналы высылаемые из рабочих потоков уходят вникуда. То есть сигнал высылается, а подписанный на него слот не вызывается.

Для проверки написал тестовую мини-программку, которая демонстрирует проблему.

Создаю очередь Queue, куда буду класть задания.
Создаю 4 потока Worker, которые в бесконечном цикле проверяют очередь.
Задание - объект простенького класса Task. Класс - наследуется от QObject, чтобы мог посылать сигнал ‘taskEnd’. Конструктор Task получает функцию, которую вызовет в потоке и параметр для этой функции.
func - функция, которая будет вызвана в потоке. Она параметром получает число, прибавляет к нему 1 и возвращает результат.
TASK_NUMBER - количество заданий, то есть количество объектов Task, которые будут обрабатыватся потоками.

Как пример работает:

щелкаем по кнопке ‘start’ - программа создает TASK_NUMBER объектов заданий, подписывает на сигнал ‘taskEnd’ обработчик - метод формы success, и кладет объект задания в Queue.

свободный поток забирает задание и запускает его. Метод run объекта задания вызывает “рабочую” функцию func, а результат ее выполнения посылает с сигналом ‘taskEnd’.
Метод success, который подписан на сигнал, считает сколько раз был вызван….

Проблема в том, что на 100 000 заданий примерно в четырех случаях из пяти приходится 99 996 - 99 999 вызовов метода success.

В PyQt бага или я чего-то не понимаю?

Python 2.6
Qt 4.6
PyQt 4.7
Windows Vista

Код:

# coding: utf-8

import sys
import Queue
import time

from threading import Thread

from PyQt4.QtGui import *
from PyQt4.QtCore import *


TASK_NUMBER = 100000

def func(i):
return i + 1

class Worker(Thread):
def run(self):
while True:
try:
t = queue.get()
except Queue.Empty:
continue
else:
time.sleep(0.02)
t.run()

class Task(QObject):
def __init__(self, target=None, args=()):
QObject.__init__(self)
self.target = target
self.args = args

def run(self):
r = self.target(*self.args)
self.emit(SIGNAL('taskEnd(PyQt_PyObject)'), r)

class Form(QWidget):
def __init__(self, queue):
QWidget.__init__(self)
self.queue = queue
self.get = 0
self.tasks = []

self.button = QPushButton('start')
QObject.connect(self.button, SIGNAL('clicked()'), self.start)
self.put_label = QLabel('Put: 0')
self.get_label = QLabel('Get: 0')

v = QVBoxLayout()
v.addWidget(self.put_label)
v.addWidget(self.get_label)
v.addWidget(self.button)
self.setLayout(v)

def start(self):
for i in xrange(TASK_NUMBER):
t = Task(func, args=[i])
self.tasks.append(t)
QObject.connect(t, SIGNAL('taskEnd(PyQt_PyObject)'), self.success)
self.queue.put(t)

self.put_label.setText('Put: ' + str(TASK_NUMBER))


def success(self, r):
self.get += 1
self.get_label.setText('Get: ' + str(self.get))



queue = Queue.Queue()

t1 = Worker()
t1.start()
t2 = Worker()
t2.start()
t3 = Worker()
t3.start()
t4 = Worker()
t4.start()


app = QApplication(sys.argv)
f = Form(queue)
f.show()
sys.exit(app.exec_())



Отредактировано (Март 16, 2010 09:52:30)

Офлайн

#2 Март 16, 2010 18:54:29

dimabest
От:
Зарегистрирован: 2009-02-12
Сообщения: 253
Репутация: +  0  -
Профиль   Отправить e-mail  

Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага?

фух, после множества экспериментов разобрался.

1. Если нужно посылать сигнал из потока - то посылать его должен не объект задания, а объект потока!
В таком случае все слоты вызываются.

Соответственно поток нужно наследовать от QThread, а программу немного переделать. Например, в класс Task передавать не только “рабочую” функцию, а и callback-функцию, которая будет вызвана в главном потоке по завершению задания.

2. Второй вариант - посылать из потоков не сигналы, а события методом QApplication.postEvent(receiver, event)

Запускал оба варианта по десятку раз на 100 тыс заданий. Все слоты в главном потоке были вызваны!



Офлайн

#3 Май 5, 2013 20:25:48

psyh0y
Зарегистрирован: 2012-09-21
Сообщения: 13
Репутация: +  0  -
Профиль   Отправить e-mail  

Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага?

Здравствуйте dimabest, если вам не сложно можете скинуть пример того, как вы решили этот вопрос.

Офлайн

#4 Май 5, 2013 20:34:09

Singularity
Зарегистрирован: 2011-07-28
Сообщения: 1387
Репутация: +  75  -
Профиль   Отправить e-mail  

Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага?

Он больше года сюда не заходил. Попробуй написать на мыло (ссылка возле ника), хотя я бы забыл что я делал три года назад

Офлайн

  • Начало
  • » GUI
  • » Некоторые сигналы, посылаемые из потока пропадают. В PyQt бага?[RSS Feed]

Board footer

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

Powered by DjangoBB

Lo-Fi Version