python为什么虽然在一个线程中的true是阻塞另一个线程

时间:2017-09-04 01:52:52

标签: python multithreading

我有两个主题。第一个(update_ds())从服务器获取数据并存储在全局变量(ds)中。第二个线程(ldk_modes())使用第一个线程中的数据并相应地执行操作。它是这样的:

def update_ds():
    global ds
    try:
        ds = get_data(5)
        print (ds)
    except:
        print('update error')
        pass
    #runs every 1 second
    threading.Timer(1, update_ds).start()

def ldk_modes():
    global old_ds
    old_ds = ds
    while True:
        if ds != old_ds:
            if ds == 1003:
                do_something()
                old_ds = ds
            elif ds == 1002:
                do_something_else()
                old_ds = ds
        else:
            pass

update_ds()
threading.Thread(target=ldk_modes).start()

我的第一个问题是,我从update_ds()打印出的内容并不是每秒打印一次。 do_something()或do_something_else()也不会快速响应服务器数据更新(我猜这最终导致update_ds()线程没有每秒更新)。为什么呢?

早些时候,我有另一个版本的代码:

ds = 0
old_ds = 0

def update_ds():
    global ds
    try:
        ds = get_data(5)
        print (ds)
    except:
        print('update error')
        pass
    #runs every 1 second
    threading.Timer(1, update_ds).start()

def ldk_modes():
    global old_ds
    while True:
        if ds != old_ds:
            if ds == 1003:
                do_something()
                old_ds = ds
            elif ds == 1002:
                do_something_else()
                old_ds = ds

update_ds()
threading.Thread(target=ldk_modes).start()

我遇到的问题是print(ds)不会每秒执行一次。但是,如果我执行“ctrl + c”,虽然我无法终止程序,但我能够每秒打印(ds)!为什么?什么是终止程序的正确方法?现在,我使用sudo kill processID,这有点不方便。

最后,

之间有什么区别
def thread_fn():
    while True:
        print("hello")

threading.Thread(target=thread_fn).start()

def thread_fn():
    print("hello")
    threading.Thread(target=thread_fn).start()

两者都会创建一个无限运行的线程,比另一个更好吗?谢谢!

1 个答案:

答案 0 :(得分:0)

我不确定Timer在这里是否合适。最好只使用两个不同的Thread实例,并在递归调用之前想要暂停1秒时包含time.sleep(1)。 (或者,使用循环而不是递归,在每次迭代中构建并删除新的Thread。)

即使采用这种设置,竞争条件也可能会对同步造成严重破坏。  目前尚不清楚您需要什么样的保证,但如果您想确保一个Thread具有控制权,请考虑使用LockCondition

这是一个简短的演示,显示了线程进程的不可靠性,使用了与原始示例中类似的global调用。

简要说明:

  • foo()线程将在new_x超过给定阈值时停止。
  • bar()主题在达到某个不平等时也会停止。
  • bar()使用new_x进行比较,foo()更新了foo()
  • import numpy as np import threading import time x = 5 new_x = 0 comparison = 6 current_ts = time.time() def foo(x, ts, thresh=0.7): print("[FOO] foo() is running.\n") global new_x, current_ts current_ts = time.time() delta = round(current_ts - ts, 4) print("[FOO] seconds elapsed since last run: {}\n".format(delta)) new_x = round(x + np.random.random(), 4) diff = abs(new_x-x) print("[FOO] x: {}, new_x: {}, diff: {}, thresh: {}\n".format(x, new_x, diff, thresh)) if new_x < x + thresh: print("[FOO] We continue.\n") time.sleep(1) foo(new_x, current_ts) else: print("[FOO] We end.\n") def bar(): print("[BAR] bar() is running.\n") bar_ts = time.time() delta = round(bar_ts - current_ts, 4) print("[BAR] ts: {}, delta from current_ts: {}\n".format(bar_ts, delta)) if (new_x <= comparison) and t1: time.sleep(1) bar() else: print("[BAR] new_x ({}) > comparison ({})...\n".format(new_x, comparison)) print("[BAR] We end.\n") 记录自上次运行以来经过的时间(以解决您每秒钟运行一次的问题)。

虽然每次运行时输出会有所不同,但下面是一些示例输出,您可以看到,在没有任何锁定的情况下,根本不清楚哪个功能在任何给定时间点都具有控制权。

t1 = threading.Thread(target=foo, args=(x, current_ts))
t1.start()

t2 = threading.Thread(target=bar)
t2.start()

现在运行:

[FOO] foo() is running.
[BAR] bar() is running.
[BAR] ts: 1504494723.83073, delta from current_ts: 0.0016
[FOO] seconds elapsed since last run: 0.0022
[FOO] x: 5, new_x: 5.5483, diff: 0.5483000000000002, thresh: 0.7
[FOO] We continue.
[BAR] bar() is running.
[FOO] foo() is running.
[FOO] seconds elapsed since last run: 1.0041
[BAR] ts: 1504494724.83534, delta from current_ts: 1.004
[FOO] x: 5.5483, new_x: 6.1234, diff: 0.5751, thresh: 0.7
[FOO] We continue.
[BAR] bar() is running.
[FOO] foo() is running.
[FOO] seconds elapsed since last run: 1.0027
[BAR] ts: 1504494725.838043, delta from current_ts: 1.0026
[FOO] x: 6.1234, new_x: 6.2092, diff: 0.08579999999999988, thresh: 0.7
[BAR] new_x (6.1234) > comparison (6)...
[FOO] We continue.
[BAR] We end.
[FOO] foo() is running.
[FOO] seconds elapsed since last run: 1.0055
[FOO] x: 6.2092, new_x: 6.9843, diff: 0.7751000000000001, thresh: 0.7
[FOO] We end.

输出:

Timer

顺便说一句,请注意,{{1}}即使您指定了{{1}},也不能保证只有一秒钟的间隔!来自the docs

  

计时器在执行其操作之前等待的时间间隔可能与用户指定的时间间隔不完全相同。