2017-09-04 65 views
0

我有兩個線程。第一個(update_ds())從服務器獲取數據並存儲在全局變量(ds)中。第二個線程(ldk_modes())使用來自第一個線程的數據並相應地執行操作。這是這樣的:python爲什麼在一個線程中真正阻塞另一個線程

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() 

我有打印(DS)同樣的問題不每秒執行一次。但是,如果我做「ctrl + c」,儘管我無法終止程序,但我能夠每秒打印一次print(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() 

兩者之間的差異將創建一個運行無限線程,是一個比其他更好嗎?謝謝!

+0

我沒有看到在python中使用線程的任何理由,它永遠不會像單線程程序那樣執行,並且通常由於[GIL](https://wiki.python.org/moin)/GlobalInterpreterLock) – alfasin

+0

@alfasin在我的較大程序中,我有多個線程,如3個線程獲取信息,以及5個線程使用這3個線程的信息來執行任務。它們不能合併,因爲我無法在所有線程中以相同的速率從服務器檢索信息。在這裏,我只寫了一個較小的程序,以確保在我花費太多時間編寫最終程序之前正確理解事情。 –

+2

如果是通過網絡檢索信息然後處理它,通常最好使用多個進程和IPC而不是蟒蛇,而不是貧困線程設施。 – pvg

回答

0

我不確定Timer在這裏是適合的。最好只使用兩個不同的Thread實例,並且在遞歸調用之前需要1秒暫停時包含time.sleep(1)。 (或者,使用循環代替遞歸,在每次迭代中構建並取下新的Thread)。

即使給定此設置,競爭條件也可能會對同步造成破壞。 您不完全清楚您需要什麼樣的擔保,但是如果您想確保一個Thread可以控制,請考慮使用LockCondition

下面是一個簡短的演示,顯示了線程進程的不可靠性,使用與原始示例類似的global調用。

簡要說明:

  • new_x跨越給定閾值的foo()線程將停止。
  • 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你不能保證得到完全一秒鐘的時間間隔,即使您指定它!從the docs

執行動作之前計時器等待的時間間隔可能與用戶指定的時間間隔不完全相同。

相關問題