如何让一个功能等待另一个功能完成再继续

时间:2020-10-11 18:40:39

标签: python kivy

我正在与您联系,社区,因为我已经用尽了所有有关如何完成这项工作的想法。

基本上,我正在做的是用相机检查护照并提取某些特征。

我需要方法send_data_to_the_server()等到第一个函数check_passport()给我期望的结果。 当捕获结果并为True时,下一个功能(连接到服务器)可以继续进行。

我试图使其与time.sleep()一起使用,因为它冻结了整个程序并变得无响应,我不得不杀死它。我发现它非常无效。

然后,我尝试将queue.Queuethreading模块一起使用。那也冻结了。

我的代码:

def check_passport(self, id, q):  # <-- this function needs to finish and return True
        self.validate_passport = NewUserValidationCamera()
        self.root.add_widget(self.validate_passport)
        if self.validate_passport._passport_passed:  # this private variable will become True at some point
            q.put((id, 'finished'))
        # while not self.validate_passport._passport_passed:
        #     time.sleep(0.5)
        # return True

def send_data_to_the_server(self):  # this method waits until method "check_passport" returns True
    ...
    ...

def register_or_login(self):
        if self.login_screen is False:
            passport_passed = False
            
            q = queue.Queue()
            thread1 = threading.Thread(target=self.check_passport, args=(1, q))
            thread2 = threading.Thread(target=self.send_data_to_the_server)
            for thread in [thread1, thread2]:
                thread.daemon = True
                thread.start()
            result = q.get()
            print(result)

就像我说的那样,无论我使用time还是threading的解决方案都会冻结该应用程序。我也使用过while not self.validate_passport._passport_passed: time.sleep(0.5),但应用程序也没有响应。

您可能还需要知道的是self.validate_passport = NewUserValidationCamera() 因为它是由__init__()方法触发的,所以启动了整个验证过程。

更新了代码以反映第二种方法的添加队列:

def register_or_login(self):
        if self.login_screen is False:
            passport_passed = False
            
            q1 = queue.Queue()
            q2 = queue.Queue()
            thread1 = threading.Thread(target=self.create_a_validation_widget_and_check_passport, args=(1, q1))
            thread2 = threading.Thread(target=self.send_data_to_the_server, args=(2, q2))
            for thread in [thread1, thread2]:
                thread.daemon = True
                thread.start()
                thread.join()
            result1 = q1.get()
            result2 = q2.get()
            print(result1)

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

我认为您可以像这样将Queue和thread.join一起使用

def __init__(self):
    self.que = queue.Queue() # will use for get the data from the check_passport
    self.thread1 = None #  will use this attribute in send_data method to wait the check_passport
    self.register_or_login()

def check_passport(self, id, q):
    self.validate_passport = NewUserValidationCamera()
    self.root.add_widget(self.validate_passport)
    if self.validate_passport._passport_passed:  
        q.put((id, 'finished'))
    return True

def send_data_to_the_server(self):  
    self.thread1.join() # The method waits for the thread1
    print("check_passport: ", self.que.get())
...

def register_or_login(self):
    if self.login_screen is False:
        passport_passed = False
        
        self.thread1 = threading.Thread(target=lamda id, q: self.que.put(self.check_passport(id, q)), args=(1, q)) 
        # the lambda function puts the result of the check_passport in the self.que
        thread2 = threading.Thread(target=self.send_data_to_the_server)
        for thread in [self.thread1, thread2]:
            thread.daemon = True
            thread.start()
        result = q.get() 
        print(result)

编辑: 在回答问题之前,我写了一个小例子,我想分享这个例子,以便您可以测试代码。

class test:
    def __init__(self):
        self.que = queue.Queue()
        self.thread1 = threading.Thread(target=lambda arg1, arg2: self.que.put(self.func_1(arg1, arg2)), args=["hello", "world"])
        self.thread1.start()
        thread2 = threading.Thread(target=self.func_2)
        thread2.start()
    
    def func_1(self, foo_1, foo_2):
        for bar in range(10):
            print(bar)
            time.sleep(1)
    
        return "{} {}".format(foo_1, foo_2)

    def func_2(self):
        self.thread1.join()
        result = self.que.get()
        print(result)
    

答案 1 :(得分:0)

所以最后我要做的就是遵循@niclaslindgren自己的建议。我称其为“ KISS”方法或也称为“ Keep It Simple Stupid”。我还接受了@Steve关于使用全局变量的说法。我不是全局变量的忠实拥护者,但是它们在编程中确实有自己的位置。 下面为我​​做了窍门:

PASSPORT_VALIDATED = False

class NewUserValidationCamera(Image):

    ...
    ...
    def update(self, dt):
        ...
        ...
        if self.names[label] == 'ma' and self._passport_keyword_passed and self._gender_check_passed:
            global PASSPORT_VALIDATED
            PASSPORT_VALIDATED = True

class MainApp(App):

    def __init__(self, **kwargs):
        super(MainApp, self).__init__(**kwargs)
        Clock.schedule_interval(self.check_for_True, 1.0)
        ...
        ...

    def check_for_True(self, dt):
        if PASSPORT_VALIDATED:
            Clock.unschedule(self.check_for_True)
            self.send_data_to_the_server()

    def send_data_to_the_server(self):  
        ...
        ...

    def register_or_login(self):
        if self.login_screen is False:
            passport_passed = False
        
            self.validate_passport = NewUserValidationCamera()
            self.root.add_widget(self.validate_passport)