Python线程自调用线程的意外行为

问题描述 投票:1回答:1

我正在测试一种可以并行运行多个任务的方法。这些任务将在并行线程中运行,我希望这些任务重复执行直到设置了全局变量。我首先尝试使用线程启动并行线程,并确保它们将正常运行。我到目前为止所拥有的:

import threading
from IPython.display import clear_output
import time

i = 0
j = 0
def main():
    global i
    global j
    t1 = threading.Thread(name = "task1", target = task1)
    t2 = threading.Thread(name = "task2", target = task2)
    t1.start()
    t2.start()

def task1():
    global i
    i += 1
    time.sleep(10)
    t1 = threading.Thread(name = "task1", target = task1)
    t1.start()

def task2():
    global j
    j -= 1
    time.sleep(10)
    t2 = threading.Thread(name = "task2", target = task2)
    t2.start()

tmain = threading.Thread(name = "main", target = main)
tmain.start()

将启动一个主线程,然后启动两个线程,它们分别运行task1和task2。要监视当前线程以及i和j的值,我运行:

while(True):
    clear_output(wait=True)
    for thread in threading.enumerate():
        print(thread)
    print(i)
    print(j)
    time.sleep(0.1)

(所有这些都在Jupyter Notebook中运行。

运行上面的脚本,我注意到了一些意外的结果。我希望在任何给定时间,任务1和任务2最多应有两个线程,但是与任务1相比,我观察到任务2的线程更多。这些不是虚假线程或完成线程,因为i和j的绝对值成比例地增长。我做了两个观察:observation 1, 1 task1 thread and 5 task2 threadsobservation 2, 3 task1 threads and 7 task 2 threads

再次,我希望任务1和任务2都应该有对称数量的线程,而且我也希望i和j的绝对值应该比它们成比例地增长。对于如何减轻这种差异或避免此问题的任何见解,将不胜感激。

python python-3.x multithreading python-multithreading
1个回答
0
投票

我在Jupyter中运行了您的代码,但没有遇到问题。

<_MainThread(MainThread, started 139735228168000)>
<Thread(Thread-1, started daemon 139735083251456)>
<Heartbeat(Thread-2, started daemon 139735074858752)>
<HistorySavingThread(IPythonHistorySavingThread, started 139735049680640)>
<Thread(task2, started 139734638634752)>
<Thread(task1, started 139734680598272)>
<Thread(task2, started 139735041287936)>
<Thread(task1, started 139734076618496)>
<Thread(task1, started 139735032895232)>
<Thread(task2, started 139734672205568)>
<Thread(task1, started 139734655420160)>
<Thread(task2, started 139734630242048)>
272
-272

但是正如您已经使用自己的代码所看到的那样,每个任务都有多个实例在运行。因此,在任务“重新开始”之后,它需要花费一些时间才能杀死自己。

您的Jupyter问题的解决方案可能是赋予主要功能重新启动被杀死的任务的控制权。这样可以确保每个任务始终仅运行一个线程。

import threading
from IPython.display import clear_output
import time

i = 0
j = 0

main_stop = False


def task1():
    global i
    i += 1
    time.sleep(4)


def task2():
    global j
    j -= 1
    time.sleep(4)


def main():
    global i
    global j
    t1 = threading.Thread(name="task1", target=task1)
    t2 = threading.Thread(name="task2", target=task2)
    t1.start()
    t2.start()
    while not main_stop:
        if not t1.is_alive():
            del t1
            t1 = threading.Thread(name="task1", target=task1)
            t1.start()
        if not t2.is_alive():
            del t2
            t2 = threading.Thread(name="task2", target=task2)
            t2.start()

    # wait for tasks to complete
    while t1.is_alive():
        time.sleep(0.1)
    while t2.is_alive():
        time.sleep(0.1)


tmain = threading.Thread(name="main", target=main)
tmain.start()

run_time = 30   # seconds
end_time = time.time() + run_time
while time.time() < end_time:

    clear_output(wait=True)
    for thread in threading.enumerate():
        print(thread)
    print(i)
    print(j)
    time.sleep(0.1)

main_stop = True
# wait for main to complete
while tmain.is_alive():
    time.sleep(0.1)

print('program completed')
© www.soinside.com 2019 - 2024. All rights reserved.