简体   繁体   English

Python如何在不干扰的情况下每n秒运行多个函数

[英]Python How to run multiple functions every n seconds without interference

So assume I'm trying to automate tasks on a webpage with selenium.因此,假设我正在尝试使用 selenium 在网页上自动执行任务。

I have multiple buttons I have to click, which take me to different parts of the page where I have to run different functions to do different tasks.我有多个按钮需要点击,这会将我带到页面的不同部分,在那里我必须运行不同的功能来完成不同的任务。 With each click of these buttons, when the corresponding tasks have been completed, a timer appears in the place of the button.每次点击这些按钮,当相应的任务完成后,一个计时器就会出现在按钮的位置。 When that timer runs out, I have to click that button again and run the corresponding function of tasks, then rinse and repeat.当那个计时器用完时,我必须再次单击该按钮并运行任务的相应功能,然后冲洗并重复。

Here is the code I've tried:这是我试过的代码:

import selenium
import threading

driver = webdriver.Chrome()
driver.get("https://example.com")

def foo1():
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    threading.Timer(timer, foo1).start()

def foo2():
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    threading.Timer(timer, foo2).start()

def foo3():
    button3 = driver.find_element_by_id("button3")
    button3.click()
    # do stuff
    timer = int(button3.text)
    threading.Timer(timer, foo3).start()

foo1()
foo2()
foo3()

Now, my problem with this is that, because there are multiple of these buttons, the scenario of one of the timers running out while another function is running can occur.现在,我的问题是,因为有多个这样的按钮,可能会出现其中一个计时器用完而另一个功能正在运行的情况。 This causes the script to click away without finishing the current sequence of tasks, thus terminating one of the threads.这会导致脚本在没有完成当前任务序列的情况下点击离开,从而终止其中一个线程。

I've tried using threading.Lock() objects but they didn't fix the issue.我试过使用 threading.Lock() 对象,但他们没有解决这个问题。 Do I have the wrong approach or am I just missing something here?我有错误的方法还是我只是在这里遗漏了什么?

The least painful solution to your problem is by using multiple webdriver objects, each of the objects in a different thread, and use a dictionary of the variables you want to be communicated.解决您的问题的最不痛苦的方法是使用多个 webdriver 对象,每个对象都在不同的线程中,并使用您想要传达的变量的字典。

import time
def foo():
    driver = webdriver.Chrome()
    driver.get("https://example.com")
    button = driver.find_element_by_id("button")
    while True:
        button.click()
        # do stuff
        timer = int(button.text)
        time.sleep(timer)

As far as I know the webdriver object is not thread-safe, so it is better to replicate it across mulitple threads , than using the same object over and over again in different threads.据我所知 webdriver 对象不是线程安全的,所以最好跨多个线程复制它,而不是在不同的线程中一遍又一遍地使用相同的对象。 Also in your solution, you spawn different threads in every different loop iteration, which can have many repercussions.同样在您的解决方案中,您会在每个不同的循环迭代中生成不同的线程,这可能会产生许多影响。 You can view this post with a similar situation in C++您可以在 C++ 中以类似情况查看帖子

From what I know, the thread initialization can be changed to solve the problem.据我所知,可以改变线程初始化来解决问题。

import selenium
import threading
import time 

driver = webdriver.Chrome()
driver.get("https://example.com")

def foo1():
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    time.sleep(timer)
    foo1()
    
def foo2():
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    time.sleep(timer)
    foo2()

t1 = threading.Thread(target=foo1)
t2 = threading.Thread(target=foo2)
t1.start()
t2.start()

You can keep the same structure of code by using a Lock object.您可以使用Lock对象保持相同的代码结构。 However, you only have to define one Lock object and acquire/release it in every function, like this:但是,您只需定义一个Lock对象并在每个函数中获取/释放它,如下所示:

import selenium
import threading

driver = webdriver.Chrome()
driver.get("https://example.com")
lock = threading.Lock()

def foo1():
    lock.acquire()
    button1 = driver.find_element_by_id("button1")
    button1.click()
    # do stuff
    timer = int(button1.text)
    lock.release()
    threading.Timer(timer, foo1).start()

def foo2():
    lock.acquire()
    button2 = driver.find_element_by_id("button2")
    button2.click()
    # do stuff
    timer = int(button2.text)
    lock.release()
    threading.Timer(timer, foo2).start()

def foo3():
    lock.acquire()
    button3 = driver.find_element_by_id("button3")
    button3.click()
    # do stuff
    timer = int(button3.text)
    lock.release()
    threading.Timer(timer, foo3).start()

foo1()
foo2()
foo3()

By doing so, you ensure that your function is atomic.通过这样做,您可以确保您的功能是原子的。 For instance, if foo2 is called while foo1 is executing, then foo2 will be executed once foo1 calls lock.release() .例如,如果foo2foo1执行时被调用,那么一旦foo1调用lock.release()就会执行foo2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM