【问题标题】:Kivy - threads, queues, clocks and Python socketsKivy - 线程、队列、时钟和 Python 套接字
【发布时间】:2014-06-27 17:29:15
【问题描述】:

我是 Kivy 的新手,也是 GUI 的新手,但对编程并不陌生。

在使用 Kivy 时,我完全想念船、独木舟和飞机。

在 30 年的编程生涯中,从机器代码、汇编、Fortran、C、C++、Java、Python,我从来没有尝试过使用 Kivy 这样的语言,因为它的文档很薄,因为它太新了。我知道它会变得更好,但我现在正在尝试使用它。

在我的代码中,我正在尝试实现队列,以便我可以获取 Python 套接字数据。在普通的 Python 编程中,我会通过队列进行 IPC - 输入数据,取出数据。

我从 Kivy 了解到,主要来自我在各种论坛上阅读的内容,但不能说我在 kivy.org 的文档中找到了它,我不能执行以下操作:

  • Kivy 需要在它自己的线程中。
  • Kivy 中的任何东西都不应该睡觉。
  • Kivy 中的任何内容都不应该阻塞 IO。

经过大量 Google 搜索后,我发现唯一有用的方法是 informative note here on StackOverFlow 。然而,虽然它几乎解决了我的问题,但答案假设我对 Kivy 的了解比我多;我不知道如何合并答案。

如果有人能花时间整理一个使用该示例的完整简短演示,或者您自己独特的完整答案之一,我将不胜感激!

这是我整理的一些短代码,但它不起作用,因为它阻塞了 get() 调用。

from Queue import Queue
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.clock import Clock
from threading import Thread

class ClockedQueue(BoxLayout):
    text1 = StringProperty("Start")

    def __init__(self):
        super(ClockedQueue,self).__init__()
        self.q = Queue()
        self.i=0
        Clock.schedule_interval(self.get, 2)

    def get(self,dt):
        print("get entry")

        val = self.q.get()
        print(self.i + val)
        self.i += 1

class ClockedQueueApp(App):

    def build(self):
        return ClockedQueue()

class SourceQueue(Queue):
    def __init__(self):
        q = Queue()
        for word in ['First','Second']:
            q.put(word)
        print("SourceQueue finished.")

def main():

    th = Thread(target=SourceQueue)
    th.start()

    ClockedQueueApp().run()
    return 0

if __name__ == '__main__':


    main()

谢谢!

【问题讨论】:

  • 这里的 Kivy 没有问题,您的代码中的其他所有内容都存在问题。 SourceQueue 什么都不做,因为它只创建一个临时局部变量。它也从未被代码中的任何其他内容引用。它不需要在线程中,绝对不应该是线程的target。至于get的阻塞,就是用get_nowaitQueue.Empty一样简单。

标签: kivy


【解决方案1】:

这是我整理的一些短代码,但它不起作用,因为它阻塞了 get() 调用。

那么您真正想做的是以非阻塞方式从队列中获取项目吗?

有多种方法可以做到这一点。最简单的似乎是在获取一个之前检查队列是否有任何项目 - Queue 有几种方法可以帮助解决这个问题,包括检查它是否为空或设置是否允许 get 阻塞(通过设置它的False 的第一个参数)。如果你只是这样做而不是自己调用get,你不会阻塞等待队列有任何项目的事情——如果它是空的或者你不能立即get任何东西,你什么都不做。

我不知道您想对从队列中获得的项目做什么,但如果是不需要很长时间的短期操作,那么您将不需要更多的东西。例如,您可以 Clock.schedule_intervalget 方法在每一帧都发生,如果队列为空,则不执行任何操作,或者如果您得到返回,则对数据进行操作。没有阻塞,也没有搞乱你自己的线程。

也可以创建自己的线程并在其中运行阻塞代码,这是处理阻塞问题的一般方法,尤其是不能拆分成小部分的任务在帧之间执行。我不知道这个细节,但它应该只涉及正常使用python线程。例如可以查看kivy的UrlRequest的来源,这可以在后台线程中下载网络源。

编辑:你的 SourceQueue 也搞砸了(你覆盖了它的 __init__ 以创建一个你不存储在任何地方的新队列),并且你的时钟调度有一个毫无意义的第三个参数 false 甚至没有定义.我不知道这里发生了什么,它可能会影响你想要做的事情,但与我上面的一般回答无关。

【讨论】:

  • 非常感谢,但就像我说的那样,我正在寻找如何执行此操作或实现我发布的 stackoverflow 链接的示例。但感谢您在回答时考虑。感谢您抓住“假”;我会尝试编辑它。
  • 我最终想做的是:1)有一个正在运行的线程可以与套接字接口。我已经在那个领域有很多需要运行的代码。 2)正在运行的线程从套接字获取数据,它是否正常工作,然后将结果推送到可以从 Kivy 中读取的队列中。 3) Kivy 读取输入队列,更新 GUI。再次感谢您的提问。
  • 我上面所说的涵盖了 kivy 部分所需的基本结构 - 类似于 Clock.schedule_interval 一个检查队列并在有任何条目时对其进行操作的函数。不过,我对线程了解不多,所以恐怕我无能为力。它应该独立于 kivy 本身,因此您可以直接研究如何在线程中运行代码的问题 - 在这种情况下,从套接字读取并推送到您的队列。
  • 不客气,感谢您的 cmets。我正在寻找一个例子。
【解决方案2】:

我终于能够创造出有用的东西。

感谢大家的建议!

这是代码(因为我是新手,Stackoverflow 不允许我在凌晨 5:00 之前将其发布为回答我自己的问题)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
#  threads_and_kivy.py
#  
'''threads_and_kivy.py
Trying to build up a foundation that satisfies the following:
    - has a thread that will implement code that:
        - simulates reads data from a Python socket
        - works on the data
        - puts the data onto a Python Queue
    - has a Kivy mainthread that:
        - via class ShowGUI
            - reads data from the Queue
            - updates a class variable of type StringProperty so it will
                update the label_text property.

'''

from threading import Thread
from Queue import Queue, Empty
import time


from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
from kivy.lang import Builder
from kivy.clock import Clock


kv='''

<ShowGUI>:
    Label:
        text: str(root.label_text)
'''

Builder.load_string(kv)

q = Queue()    


class SimSocket():
    global q

    def __init__(self, queue):
        self.q = queue

    def put_on_queue(self):
        print("<-----..threaded..SimSocket.put_on_queue(): entry")
        for i in range(10):
            print(".....threaded.....SimSocket.put_on_queue(): Loop " + str(i))
            time.sleep(1)#just here to sim occassional data send
            self.some_data = ["SimSocket.put_on_queue(): Data Loop " + str(i)]
            self.q.put(self.some_data)
        print("..threaded..SimSocket.put_on_queue(): thread ends")

class ShowGUI(BoxLayout):
    label_text = StringProperty("Initial - not data")
    global q

    def __init__(self):
        super(ShowGUI, self).__init__()
        print("ShowGUI.__init__() entry")
        Clock.schedule_interval(self.get_from_queue, 1.0)

    def get_from_queue(self, dt):
        print("---------> ShowGUI.get_from_queue() entry")
        try:
            queue_data = q.get(timeout = 5)
            self.label_text = queue_data[0]
            for qd in queue_data:
                print("SimKivy.get_from_queue(): got data from queue: " + qd)
        except Empty:
            print("Error - no data received on queue.")
            print("Unschedule Clock's schedule")
            Clock.unschedule(self.get_from_queue)


class KivyGui(App):
    def build(self):
        return ShowGUI()



def main():

    global q
    ss = SimSocket(q)

    simSocket_thread = Thread(name="simSocket",target=ss.put_on_queue)
    simSocket_thread.start()

    print("Starting KivyGui().run()")

    KivyGui().run()


    return 0

if __name__ == '__main__':

    main()

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-01
  • 2013-02-16
  • 1970-01-01
相关资源
最近更新 更多