スレッドは、コードを同時に実行する方法です。つまり、関数Aを実行することができますが、終了する前に、関数Bを開始することができます。同時に実行する必要はありません(並列プログラミング)。あなたが時間を止めてコード内で何が起こっているのかを見ると、関数Aはまだいくつかの文を実行していますが、関数Bの文も実行されていることがわかります。
Pythonスレッドモジュールでは、各スレッドはいくつかの引数を持つ関数(またはメソッド)であり、起動時に関数本体が実行されます。関数が戻ると、スレッドは実行され、スレッドの状態はnot alive
(threading.Thread.is_alive()
参照)に変わります。
だから我々は、関数/メソッド参照し、可能な引数を渡すことで、スレッドを作成します。
from threading import Thread
simple_thread = Thread(target=func_with_no_args)
thread_with_args = Thread(target=my_function, args=(arg1, arg2))
そして、我々は関数の本体を実行するために、スレッドを開始。
simple_thread.start()
thread_with_args.start()
しかし、現在のスレッドの流れは継続しています(現在のスレッドは、プログラムのメインスレッドが常に実行を開始します)。したがって、機能(func_with_no_args
またはmy_function
)が完了するまで待つ必要はありません。
そして、我々はスレッドで実行された関数が終了したかどうかを確認する必要がある場合、それは生きているならば、我々は確認することができます。
simple_thread.is_alive() # return bool
そして、我々は、スレッド内の関数の実行が終了するまで待機したい場合は、我々はjoin
スレッドをすることができます。また、終了時にスレッドをjoin
にするのも良いことです。
simple_thread.join()
これは、プログラムがIOとの間でデータの準備が整うのを待っている間に、他の処理を行うことができるためです。
私がしている3つの変数(フロート)かかりスレッドを作成しようとしています...
は、私はあなたが何かを達成したいと仮定して、あなたはツールとしてのスレッドを使用しています。私はスレッドを作成することはここの目標ではなく、あなたが望むものを達成する方法であることを意味します。 質問にはアプリケーションの詳細が表示されないので、正確なコードやサンプルは提供できませんので、アプリケーションにそのアイデアを適用できることを希望する抽象的な/一般的な回答に進みます。
アプリケーションはどこかのデータ(IO)からデータを受け取り、30msごとに新しいデータをardunio(IOのように機能する)に送るべきだと思います。したがって、アプリケーションには2 IOアームがあり、1つはデータを受信し、もう1つはardunioに送信します。したがって、スレッドを使用すると正当性があります。
私たちは2つの機能を持つことができます.1つはデータの読み込み、1はardunioの更新です。それらを2つのスレッドthread_read
(データを読み込む)とthread_ardunio
(ardunioを更新する)で実行します。
もしそうなら、スレッド間で情報を共有する方法が必要です。スレッドはメモリ(プロセスメモリ内で、変数からアクセス可能)を使いやすくするため、両方の関数からアクセス可能な変数を使用できます。変数が1スレッドで更新されると、もう1スレッドは更新された結果も表示します。
storage = None
def read_data():
global storage
# read data from DB, web API, user input, etc.
# maybe in a loop to keep receiving data. Or generate the data from here
storage = (cX, cY, angle)
def send_to_ardunio():
global storage
# send storage data to ardunio, maybe in a loop
# sleeping 30ms after each update
thread_read = Thread(target=read_data)
thread_ardunio = Thread(target=send_to_ardunio)
thread_read.start()
thread_ardunio.start()
これは1つの方法です。 IMHOはそれほどきれいではありません。そこにはグローバル変数があります。変数を削除するにはどうすればよいですか?キューを使用できます(queue.Queue
参照)。
キューはスレッド間で通信するのに適した方法だと思います。したがって、データを持つスレッドはそれらをキュー(a.k.aプロデューサ)に置き、もう一方のスレッドはキューからアイテムを選択します(a.k.aコンシューマ)。
このような何か:
def read_data(queue_):
# read data from DB, web API, user input, etc.
# maybe in a loop to keep receiving data, or generate the data from here
data = (cX, cY, angle)
queue_.put(data)
def send_to_ardunio(queue_):
# send data to ardunio, maybe in a loop
# sleeping 30ms after each update
data = queue_.get()
cX, cY, angle = data
queue_ = Queue() # this will be used to transfer data
thread_read = Thread(target=read_data, args=(queue_,))
thread_ardunio = Thread(target=send_to_ardunio, args=(queue_,))
thread_read.start()
thread_ardunio.start()
が良く見えます。
ここで、関数が実行されるまで待つ必要があります。したがって、スレッド上でjoin
メソッドを呼び出すことができます。また今回は、データを読むのにどれくらいの時間がかかるかを制御できると仮定して自由を取った。新しいデータで30msごとにardunioを更新する必要がある場合、プロデューサは周波数を調整することができ、消費者はまったく躊躇せずに消費することができます。
また、スレッドの生成/消費を停止するように指示する方法が必要です。 Event
(threading.Event
を参照)を使用することができます。また、単純に合意しただけで、キュー上のデータは消費者が停止する必要があることを表します。
def read_data(queue_):
while True:
# calculate/get cX, cY, angle
queue_.put((cX, cY, angle))
# sleep 30ms
# when we finished producing data, put something to the queue to tell the consumer there is no more data. I'll assume None is good option here
queue_.put(None)
def send_to_ardunio(queue_):
while True:
data = queue_.get()
if data is None:
break
cX, cY, angle = data
# update ardunio, because the data is updated every 30ms on the producer, we don't need to do anything special. We can just wait when the data is ready, we'll update.
queue_ = Queue()
thread_read = Thread(target=read_data, args=(queue_,))
thread_ardunio = Thread(target=send_to_ardunio, args=(queue_,))
thread_read.start()
thread_ardunio.start()
thread_read.join()
thread_ardunio.join()
上記のコードは、プロデューサ(thread_read
)がデータを生成停止する知っているであろうことを前提としています。
これが当てはまらない場合は、Event
を使用して、両方の機能をトリガして生成と消費を停止することができます。
最後に、スレッドを結合するときに私は小さなキャッチを経験しました。メインスレッドが他のスレッドに参加している場合、ブロックされ、SIGINTにうまく応答しません。したがって、(Ctrl + Cを押すかSIGINTを送ることによって)Pythonプロセスを停止しようとすると、終了しません。
ただし、タイムアウトを指定してスレッドに参加しようとすることはできます。だから毎回、メインスレッドは受信信号を見て、それらを処理することができます。
def read_data(queue_, should_stop):
while not should_stop.is_set():
# calculate/get cX, cY, angle
queue_.put((cX, cY, angle))
# sleep 30ms
def send_to_ardunio(queue_, should_stop):
while not should_stop.is_set():
data = queue_.get()
cX, cY, angle = data
# update ardunio
def tell_when_to_stop(should_stop):
# detect when to stop, and set the Event. For example, we'll wait for 10 seconds and then ask all to stop
time.sleep(10)
should_stop.set()
queue_ = Queue()
should_stop = Event()
thread_stop_decider = Thread(target=tell_when_to_stop, args=(should_stop,))
thread_read = Thread(target=read_data, args=(queue_, should_stop))
thread_ardunio = Thread(target=send_to_ardunio, args=(queue_, should_stop))
thread_read.start()
thread_ardunio.start()
thread_stop_decider.start()
try:
while thread_read.is_alive():
thread_read.join(1)
except KeyboardInterrupt:
should_stop.set()
thread_read.join()
thread_ardunio.join()
thread_stop_decider.join()