python中线程之间的回调

时间:2017-10-31 19:58:21

标签: python multithreading user-interface

我在理解回调时遇到了一些麻烦。我有以下用例:

从我的gui我开始一个名为videoDown的新线程(这是它自己的类)。从这个线程我想把数据推回到gui,我已经实现了回调系统。但要更新GUI我需要在GUI线程而不是我当前所在的线程(这是videoDown线程)。

我启动线程的代码(类下载器):

def download_single(self, json_data):
    form_data = json.loads(json_data)
    print self.app
    url = form_data["name"]
    dt = form_data["dt"]  # Download type is audio or video
    videoDown = videoDownload(url, dt, self.dd,callback=self.cb,callback_args=("hello", "world",self.app))
    videoDown.start()

videoDownload thread:

class videoDownload(threading.Thread):
def __init__(self,url, dt, dd,callback=None, callback_args=None, *args, **kwargs):
    threading.Thread.__init__(self)
    self.callback = callback
    self.url = url
    self.dt = dt
    self.dd = dd
    self.callback_args = callback_args
    if self.callback is not None:
        self.callback(*self.callback_args)

def run(self):
    if self.url.__contains__("https://www.youtube.com/watch?v="):
        if self.dt == 'audio':
            self._downloadVid(self.url, vid=False)
        else:
            self._downloadVid(self.url, vid=True)
    else:
        print "Incorrect url"

def _downloadVid(self, url, vid=False, order_reverse=False, vinName=None):
    video = pafy.new(url)

    if self.callback is not None: //<--CALLBACK IN HERE
        self.callback(*self.callback_args)
    streams = video.allstreams
    for stream in streams:
        print stream

    print video
    name = u''.join(video.title).encode('utf8')
    name = re.sub("[<>:\"/\\|?*]", "", name)
    if not vid:
        file = video.getbestaudio()
    else:
        file = video.getbest()
    if (order_reverse):
        file.download(self.dd + vinName + name + ".mp4", quiet=False, callback=self.mycb)
    else:
        file.download(self.dd + name + ".mp4", quiet=False, callback=self.mycb)

回调(也在类Downloader中):

def cb(self,param1, param2,param3):
    print threading.current_thread()

我是如何实现它的,所以我可以将当​​前线程设置为此视频下载线程时,将我的视频下载线程中的数据返回给gui线程。

我需要改变什么,我几个小时都在苦苦挣扎。

〜问候

2 个答案:

答案 0 :(得分:1)

也许使用Queue而不是回调。初始化主线程中的队列,将对象传递给下载线程,并调用Queue对象上的get()来阻塞,直到项目传递给它。

stdafx.h

在videoDownload对象中,通过Queue

将数据传回主线程
q = Queue.Queue()
d = ("hello", "world", self.app)
videoDown = videoDownload(url, dt, self.dd, queue=q, data=d)
returned_data = q.get()

答案 1 :(得分:1)

来自luke的大量帮助。我想出了以下答案。

在我的javascript中,我创建了以下功能:

    function start() {
        Downloader.trydasd(); //ignore the nameconvention. We all try sometimes
        setTimeout(start, 3000);
    }

    start();

这是在python中实现的,如下所示:

@htmlPy.Slot()
def trydasd(self):
    if not self.q.empty():
        print self.q.get(block=False)

之后我改变了我的init来创建这样的队列:

    def __init__(self, app):
        super(Downloader, self).__init__()
        # Initialize the class here, if required.
        self.app = app
        self.q = Queue.Queue()

之后我将download_single函数更改为:

 def download_single(self, json_data):
    form_data = json.loads(json_data)
    print self.app
    url = form_data["name"]
    dt = form_data["dt"]  # Download type is audio or video
    d = ("hello", "world", self.app)
    videoDown = videoDownload(url, dt, self.dd, queue=self.q, data=d)
    videoDown.start()

最后我的下载主题是:

class videoDownload(threading.Thread):
def __init__(self,url, dt, dd,queue=None,data=None, *args, **kwargs):
    threading.Thread.__init__(self)
    self.queue = queue
    self.data = data
    self.url = url
    self.dt = dt
    self.dd = dd

def run(self):
    if self.url.__contains__("https://www.youtube.com/watch?v="):
        if self.dt == 'audio':
            self._downloadVid(self.url, vid=False)
        else:
            self._downloadVid(self.url, vid=True)
    else:
        print "Incorrect url"

def _downloadVid(self, url, vid=False, order_reverse=False, vinName=None):
    video = pafy.new(url)
    if self.queue and self.data:
        self.queue.put(video)

    name = u''.join(video.title).encode('utf8')
    name = re.sub("[<>:\"/\\|?*]", "", name)
    if not vid:
        file = video.getbestaudio()
    else:
        file = video.getbest()
    if (order_reverse):
        file.download(self.dd + vinName + name + ".mp4", quiet=False, callback=self.mycb)
    else:
        file.download(self.dd + name + ".mp4", quiet=False, callback=self.mycb)

这解决了我的问题,任何其他方式都不起作用,并会阻止用户界面。

非常感谢卢克!