Kivy 和 Flask 线程在 Python2 中相互阻塞

本文介绍了Kivy 和 Flask 线程在 Python2 中相互阻塞的处理方法,对大家解决问题具有一定的参考价值

问题描述

我有以下设置:Kivy 1.11.1、Flask 1.1.1 和 Python 2.7.13.我想获取 JSON 请求,但在 Kivy GUI 运行时,我被困在 Flask 应用程序不获取请求.即使在单独的线程中运行,它们也会相互阻塞.

I have the following setup: Kivy 1.11.1, Flask 1.1.1 and Python 2.7.13. I want to fetch a JSON request but I am stuck at Flask app does not fetch requests while the Kivy GUI is running. Even when run in separate threads they block each other.

主要的api脚本eg_api.py:

The main api script eg_api.py:

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

# kivy modules first, if not Kivy may cause problems
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
kivy.require('1.10.0')

# common modules
import re
import sys
import time
import signal
import threading
from datetime import datetime

# Flask & similar modules
from flask import Flask
from flask import request
from flask_restful import reqparse, abort, Api, Resource
from flask_httpauth import HTTPBasicAuth
import json, ast
import urlparse
import eventlet
from eventlet import wsgi

# imports from other files
from eg_wrapper import Actions

# async server setup
eventlet.monkey_patch()
app = Flask(__name__)
api = Api(app)
auth = HTTPBasicAuth()

# user access setup
USER_DATA = {
    "admin": "SuperSecretPwd"
}

# global variable
data_json = None

@auth.verify_password
def verify(username, password):
    if not (username and password):
        return False
    return USER_DATA.get(username) == password

def start_Flask():
    print("Starting Flask...")
    #app.run(port=5000, debug=False)     #specify separate port to run Flask app
    wsgi.server(eventlet.listen(('', 5000)), app)     # deploy as an eventlet WSGI server

def signal_handler(signal, frame):
    print " CTRL + C detected, exiting ... "
    exit(0)


#######################   flask classes   #########################
class Load(Resource):
    @auth.login_required
    def post(self):
        print "**********  class Load(Resource): *****************"
        data = request.json
        print data
        lw = Actions()
        data_json = lw.Parse_Load_Request(data)
        res = {'data': data_json}
        return res, 201


#######################   resource calls   #######################
api.add_resource(Load, '/load')


########################## kivy screen classes ###############################
class MainScreen(Screen):
    pass


########################## kivy popup classes ###############################

# main screen        
class MainScreen(Screen):
    def __init__(self, **kwargs):
        self.name="MAIN SCREEN"
        super(Screen, self).__init__(**kwargs)

# popup        
class MessageBox10(Popup):
    def __init__(self, obj, **kwargs):
        super(MessageBox10, self).__init__(**kwargs)
        self.obj = obj

# popup        
class MessageBox20(Popup):
    def __init__(self, obj, **kwargs):
        super(MessageBox20, self).__init__(**kwargs)
        self.obj = obj

class Kivy(App):
    w_MessageBox10_1 = "Message_10_1"
    w_MessageBox10_2 = "Message_10_2"
    w_MessageBox10_3 = "Message_10_3"
    w_MessageBox10_4 = "Message_10_4"
    w_MessageBox20_1 = "Message_20_1"
    w_MessageBox20_2 = "Message_20_2"
    w_MessageBox30_1 = "Message_30_1"
    w_MessageBox30_2 = "CONFIRM"
    w_MessageBox30_3 = "CANCEL"

    def do(self):
        print "do something"

    def cancel(self):
        print "load cancelled by user"

    def exit(self):
        print "exiting..."
        exit(1)

    def enter(self):
        # open the init file and write the parameters
        print "********** def enter(self): popup = MessageBox20(self) *************************"
        popup = MessageBox20(self)
        popup.open()

    def build(self):
        sm = Builder.load_string("""

ScreenManager
    MainScreen:
        size_hint: 1, .7
        auto_dismiss: False
        title: app.w_MessageBox10_1       
        title_align: "center"

        BoxLayout:
            orientation: "vertical"
            Label:
                text: app.w_MessageBox10_2
            BoxLayout:
                orientation: "horizontal"
                spacing: 10
                size_hint: 1, .5
                Button:
                    text: app.w_MessageBox30_2  # CONFIRM
                    on_press:
                        app.enter()
                Button:
                    text: app.w_MessageBox30_3  # CANCEL
                    on_press:
                        app.exit()

<MessageBox20>:
    size_hint: 1, .7
    auto_dismiss: False
    title: app.w_MessageBox20_1       
    title_align: "center"

    BoxLayout:
        orientation: "vertical"
        Label:
            text: app.w_MessageBox20_2
        BoxLayout:
            orientation: "horizontal"
            spacing: 10
            size_hint: 1, .5
            Button:
                text: app.w_MessageBox30_2  # "CONFIRM"
                on_press:
                    app.do()
                    root.dismiss()
            Button:
                text: app.w_MessageBox30_3  # "CANCEL"
                on_press:
                    app.cancel()
                    root.dismiss()  

        """)

        return sm


if __name__ == '__main__':    

    #CTRL+C signal handler
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    # start the first thread
    t1 = threading.Thread(target=start_Flask)
    t1.start()

    # start the second thread
    t2 = threading.Thread(target=Kivy().run)
    t2.start()

    # join the two threads
    t1.join()
    t2.join()

包装脚本 eg_wrapper.py:

The wrapping script eg_wrapper.py:

#!/usr/bin/python2.7 python2.7
#!/bin/sh -i
# -*- coding: utf-8 -*-

"""
This program executes actions called by eg_api.py.
"""

import os
import signal
import re
import json, ast
import sys
import subprocess
import multiprocessing
from subprocess import PIPE, STDOUT
from datetime import datetime

# to solve the send_file issue
import eventlet
eventlet.monkey_patch()


class Actions:

    def Parse_Load_Request(self, request):     # parse the JSON data
        timestamp = datetime.now()
        code = "200"
        id_code = "0000"
        data = request
        task = ""
        res={}
        list_of_tasks = []
        print "********** def Parse_Load_Request(self, r): print data without uni-code chars *****************************"
        data = ast.literal_eval(json.dumps(data)) # Removing uni-code chars
        print "********** def Parse_Load_Request(self, r): print keys for data *****************************"
        print(data.keys())    # print all the keys in the dictionary first
        res["code"] = code
        res["timestamp"] = str(timestamp)
        res["id"] = id_code
        res["data"] = str(list_of_tasks)
        res["task"] = task
        return res


def signal_handler(signal, frame):
    exit(1)


def main():
    # CTRL+C signal handler
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    #the sys.argv parameter is a list of arguments from the command line
    ex = Actions()
    sys.exit(app.exec_())


if __name__ == "__main__":
    # define the stuff
    global mainProcess, mainProcessPid

    # execute main
    main()

程序

我运行 eg_api.py 并且 Flask 和 Kivy 确实作为线程启动.他们启动并运行,eventlet 正在侦听并且带有第一个弹出窗口的 Kivy 窗口启动.然后我发送请求.

I run the eg_api.py and Flask and Kivy do start as threads. They get up and run, eventlet is listening and the Kivy window with the first popup gets up. Then I send the request.

输出

(py2) parovelb@Latitude-E6510:~/Desktop/Python2$ python eg_api.py 
[INFO   ] [Logger      ] Record log in /home/parovelb/.kivy/logs/kivy_19-12-23_34.txt
[INFO   ] [Kivy        ] v1.10.1
[INFO   ] [Python      ] v2.7.15rc1 (default, Nov 12 2018, 14:31:15) 
[GCC 7.3.0]
[INFO   ] [Factory     ] 194 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2
Starting Flask...
 (15549) wsgi starting up on http://0.0.0.0:5000
[INFO   ] [Window      ] Provider: sdl2(['window_egl_rpi'] ignored)
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] Backend used <gl>
[INFO   ] [GL          ] OpenGL version <3.3 (Compatibility Profile) Mesa 19.0.8>
[INFO   ] [GL          ] OpenGL vendor <nouveau>
[INFO   ] [GL          ] OpenGL renderer <NVA8>
[INFO   ] [GL          ] OpenGL parsed version: 3, 3
[INFO   ] [GL          ] Shading version <3.30>
[INFO   ] [GL          ] Texture max size <8192>
[INFO   ] [GL          ] Texture max units <16>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
[INFO   ] [Base        ] Start application main loop
[INFO   ] [GL          ] NPOT texture support is available
********** def enter(self): popup = MessageBox20(self) *************************
do something
exiting...
[INFO   ] [Base        ] Leaving application in progress...
 (15549) accepted ('192.168.3.88', 53418)
**********  class Load(Resource): *****************
{u'position': u'b1', u'tasks': [{u'code': u'24258146312', u'actionDescription': u'Preleva 20ml di glucosio dalla sacca', u'barcode': u'000001', u'results': [u'returnCode'], u'actions': [{u'returnCode': u'200', u'type': u'CONFIRM', u'label': u'Conferma'}, {u'returnCode': u'400', u'type': u'ABORT', u'label': u'Annulla'}], u'itemName': u'Glucosio 100ml'}, {u'code': u'24258146313', u'actionDescription': u'Leggi il barcode e il codice RFID', u'itemName': u'Glucosio 100ml', u'barcode': u'000001', u'results': [u'returnCode', u'barcode', u'rfid'], u'actions': [{u'returnCode': u'200', u'type': u'CONFIRM', u'label': u'Conferma'}, {u'returnCode': u'400', u'type': u'ABORT', u'label': u'Annulla'}], u'type': u'BARCODE_CHECK'}, {u'code': u'24258146314', u'itemName': u'Glucosio 100ml', u'actionDescription': u'Posiziona la sacca nello slot 1', u'actions': [{u'returnCode': u'200', u'type': u'CONFIRM', u'label': u'Conferma'}, {u'returnCode': u'400', u'type': u'ABORT', u'label': u'Annulla'}], u'results': [u'returnCode']}], u'weight': u'133.15'}
********** def Parse_Load_Request(self, r): *****************************
********** def Parse_Load_Request(self, r): print data without uni-code chars *****************************
********** def Parse_Load_Request(self, r): print keys for data *****************************
['position', 'tasks', 'weight']
 192.168.3.88 - - [23/Dec/2019 11:08:44] "POST /load HTTP/1.1" 201 247 0.004312

问题

当我发送请求时,Flask 没有获取请求.当我按下第一个弹出窗口的按钮时,Flask 仍然没有获取请求.当我按下第二个弹出窗口上的按钮时,Flask 仍然没有获取请求.无论我如何启动线程,Kivy 都会阻止 Flask.我检查了 这个线程 但我没有帮助.我做错了什么?

Flask does not fetch the request when I send it. When I press the button of the first popup, Flask still does not fetch the request. When I press the button on the second popup, Flask still does not fetch the request. Kivy blocks Flask no matter the order how I start the threads. I checked this thread but I does not help. What am I doing wrong?

推荐答案

这不是问题的确切答案,但它是 Flask 阻塞 Kivy 的替代解决方案,反之亦然.我尝试了多处理,似乎它确实有效.希望它可以帮助某人,如果一些专家编码决定升级答案,欢迎这样做.

It is no exactly the answer to the question but it is an alternative solution to the Flask blocking Kivy and vice versa. I gave it a try with multiprocessing and it seems it does the work. Hope it helps somebody and if some expert coder decide to upgrade the answer is welcome to do so.

代码

#!/usr/bin/python2.7 python2.7
# -*- coding: utf-8 -*-

# kivy modules first, if not Kivy may cause problems
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
kivy.require('1.10.0')


# common modules
import sys
import signal
from multiprocessing import Process


# Flask & similar modules
from flask import Flask
from flask_restful import reqparse, abort, Api, Resource
import eventlet
from eventlet import wsgi


# async server setup
eventlet.monkey_patch()
app = Flask(__name__)
api = Api(app)


def start_Flask():
    print("Starting Flask...")
    # deploy as an eventlet WSGI server on port 5000
    wsgi.server(eventlet.listen(('', 5000)), app)     


def signal_handler(signal, frame):
    # for fetching CTRL+C and relatives
    print " CTRL + C detected, exiting ... "
    exit(1)


# Kivy screen class
class MainScreen(Screen):
    def __init__(self, **kwargs):
        self.name="MAIN SCREEN"
        super(Screen, self).__init__(**kwargs)


# Kivy app class
class Kivy(App):
    w_MessageBox10_1 = "MAIN SCREEN"
    w_MessageBox10_2 = "One golden glance of what should be"
    w_MessageBox30_2 = "CHORUS"
    w_MessageBox30_3 = "EXIT"


    # exit button action   
    def exit(self):
        print "exiting... one shaft of light will show the way..."
        p1.terminate()  # terminate Flask by pressing on cancel
        exit(1)


    # do magic button action
    def do_magic(self):
        # your code goes here or maybe not
        print "***** it's a kind of magic *************************"


    # Kivy UI builder file
    def build(self):
        sm = Builder.load_string("""

ScreenManager
    MainScreen:
        size_hint: 1, .7
        auto_dismiss: False
        title: app.w_MessageBox10_1       
        title_align: "center"

        BoxLayout:
            orientation: "vertical"
            Label:
                text: app.w_MessageBox10_2
            BoxLayout:
                orientation: "horizontal"
                spacing: 10
                size_hint: 1, .5
                Button:
                    text: app.w_MessageBox30_2  # DO MAGIC
                    on_press:
                        app.do_magic()
                Button:
                    text: app.w_MessageBox30_3  # EXIT
                    on_press:
                        app.exit()


        """)

        return sm


if __name__ == '__main__':    

    # #CTRL+C signal handler
    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    global p1
    p1 = Process(target=start_Flask)    # assign Flask to a process
    p1.start()                          # run Flask as process
    Kivy().run()                        # run Kivy UI

这篇关于Kivy 和 Flask 线程在 Python2 中相互阻塞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,WP2

WordPress使用python会话上载文件

我需要上传图像到wordpress编程,理想情况下没有安装额外的插件。不过,我对涉及插件的最佳实践持开放态度。到目前为止,我已经能够使用会话登录和移动站点,但是当我尝试将文件上载到媒体时-新建.php或异步-上传.php我收到以下错误消息The file is a test text file with a single line (also the upload limit on the site is 1GB) so it\"s not the common file size limit. This ...

日期:2021-08-21 05:00:01 浏览:784

压缩序列化的Python数据最节省空间的方法是什么?

本文介绍了压缩序列化的Python数据最节省空间的方法是什么?的处理方法,对大家解决问题具有一定的参考价值 问题描述 发件人the Python documentation:默认情况下,Pickle数据格式使用相对紧凑的二进制表示。如果您需要最佳大小特性,您可以高效地压缩酸洗数据。我将在一个运行了几个小时的过程结束时序列化...

日期:2022-06-23 08:50:34 浏览:753

在Python中,有没有一种方法可以将一个单词分割成等分?

本文介绍了在Python中,有没有一种方法可以将一个单词分割成等分?的处理方法,对大家解决问题具有一定的参考价值 问题描述 几周前我问了这个问题,得到了答案this is the original post但我需要将输出分成相等的部分,无论字符串的长度如何,所以在我发布的第一个帖子中,我得到了这个答案,它很好地工作了,这要...

日期:2022-06-24 06:52:06 浏览:475

如何在 Google AppEngine Python37 中获取凭据

本文介绍了如何在 Google AppEngine Python37 中获取凭据的处理方法,对大家解决问题具有一定的参考价值 问题描述 我在 AppEngine Python3.7 标准中启动了新应用.I started new app in AppEngine Python3.7 stadard.我正在尝试使用以下代码段...

日期:2022-06-24 09:00:27 浏览:549

为什么 python 字符串和元组是不可变的?

本文介绍了为什么 python 字符串和元组是不可变的?的处理方法,对大家解决问题具有一定的参考价值 问题描述 我不确定为什么字符串和元组是不可变的;使它们不可变的优点和缺点是什么?I am not sure why strings and tuples were made to be immutable; what ar...

日期:2022-06-24 09:00:30 浏览:885

使用 Python 解析 Gmail 并将所有早于日期的内容标记为“已读"

本文介绍了使用 Python 解析 Gmail 并将所有早于日期的内容标记为“已读"的处理方法,对大家解决问题具有一定的参考价值 问题描述 长话短说,我创建了一个新的 gmail 帐户,并将其他几个帐户关联到该帐户(每个帐户都有 1000 条消息),我正在导入这些帐户.所有导入的邮件都以未读的形式到达,但我需要它们显示为已...

日期:2022-06-24 10:00:29 浏览:809

了解python线程错误

本文介绍了了解python线程错误的处理方法,对大家解决问题具有一定的参考价值 问题描述 阅读http://bugs.python.org/msg160297,我可以看到Stephen White编写的一个简单脚本,它演示了该异常是如何导致python线程出错的Exception AttributeError: Attri...

日期:2022-06-24 21:00:28 浏览:946

从python调用url时获取“错误"的页面源

本文介绍了从python调用url时获取“错误"的页面源的处理方法,对大家解决问题具有一定的参考价值 问题描述 尝试从网站检索页面源时,得到的文本与通过 Web 浏览器查看相同页面源时完全不同(且更短).Trying to retrieve the page source from a website, I get a c...

日期:2022-06-25 01:00:31 浏览:598

基于 Python 类的装饰器,带有可以装饰方法或函数的参数

本文介绍了基于 Python 类的装饰器,带有可以装饰方法或函数的参数的处理方法,对大家解决问题具有一定的参考价值 问题描述 我见过很多 Python 装饰器的例子:I've seen many examples of Python decorators that are:函数样式装饰器(包装函数)类样式装饰器(实现 __...

日期:2022-06-25 04:00:31 浏览:929

用python解析outlook .msg文件

本文介绍了用python解析outlook .msg文件的处理方法,对大家解决问题具有一定的参考价值 问题描述 环顾四周,没有找到满意的答案.有谁知道如何使用 Python 解析 Outlook 中的 .msg 文件?Looked around and couldn't find a satisfactory answer...

日期:2022-06-25 06:00:30 浏览:640