Python3: 並行処理?非同期処理?をやってみる

はじめに

バイトの片山です。

卒論が無事に終わり(?)、残るは通常授業の課題だけになりました。
卒業確定の書面を正式にもらう3月までは気が抜けない日々ですが、息抜きがてら、久しぶりにBPSに来てみました。

ほぼ半年ぶりに来たのでバイトの登録が抹消されているのではないかと心配していましたが、
案の定、入退管理システムに引っかかりました。
「登録されてません」の文字列が見えた瞬間、頭が真っ白になったのはいうまでもありません。

久しぶりに来たので、何を書こうか戸惑っているところなのですが、とりあえず、卒業研究で使った、
Python3での並行処理というか非同期処理のやり方を掲載しようかと思います。

並行処理と非同期処理の違いがよくわかっていませんが、並列処理は「一つの仕事を分担して高速化する」なのに対して、
並行処理とか非同期処理は「複数の仕事を同時に走らせる」イメージ、であってるのでしょうか……

とにもかくにも、Python3で「複数の仕事を同時に走らせる」のをやっていこうと思います。

Python3で非同期処理?並行処理?をやってみる

サンプルコード

環境はPython3(3.5.2)です。

ひとまずは簡単なものからやっていこうと思います。
というか簡単なものしかできませんのであらかじめご了承ください。

#-*- coding:utf-8 -*-
import threading
import time

def send00():
    while True:
        print("ようこそ")
        time.sleep(1)

def send01():
    while True:
        print("ジャパリパー")
        time.sleep(1.5)

if __name__ == "__main__":
    th00 = threading.Thread(target=send00, name="th00", args=())
    th01 = threading.Thread(target=send01, name="th01", args=())
    th00.start()
    th01.start()

まず、threadingモジュールをimportします。これがないと話にならないみたいです。
都合上timeもimportしています。
こいつを実行してみると、send00()send01()がずっと並行して動いているのがわかると思います。

$ python3 multithread.py                                                                                    
ようこそ
ジャパリパー
ようこそ
ジャパリパー
・
・
・

これを並行処理とか非同期処理といっていいのかわからないですが、
ひとまずそれっぽい感じな気がしますね。

printするだけだとイマイチわかりにくいし、楽しくないということで、OSC(Open Sound Control)と組み合わせてみたいと思います(参考記事)。

#-*- coding:utf-8 -*-
import threading
import time
import argparse

from pythonosc import osc_message_builder
from pythonosc import udp_client

IP = "127.0.0.1"
PORT = 8778

message00 = "ぁ〜ん"
message01 = "ぅひ〜ん"

parser = argparse.ArgumentParser()
parser.add_argument("--ip", default=IP, help="The ip of the OSC server")
parser.add_argument("--port", type=int, default=PORT, help="The port of the OSC server is listening on")
args = parser.parse_args()
client = udp_client.UDPClient(args.ip, args.port)

def send00():
    while True:
        msg = osc_message_builder.OscMessageBuilder(address="/test00")
        msg.add_arg(message00)
        msg = msg.build()
        client.send(msg)
        time.sleep(1)

def send01():
    while True:
        msg = osc_message_builder.OscMessageBuilder(address="/test01")
        msg.add_arg(message01)
        msg = msg.build()
        client.send(msg)
        time.sleep(1)

def main():
    global message00
    message00 = input("input message00 >>>")
    global message01
    message01 = input("input message01 >>>")

if __name__ == "__main__":
    th00 = threading.Thread(target=send00, name="th00", args=())
    th01 = threading.Thread(target=send01, name="th01", args=())
    th00.start()
    th01.start()
    while True:
        main()

実行して、ポート8778番をMax/MSPやその他のアプリケーションでモニターしてみると、

max

トライアル版のMax/MSP(30日)を使ってるのは笑ってください。コンソールの方でinput message00 >>>とかに入力してやると、OSCで送られるメッセージも変わるのがわかると思います。

さっきよりはなんとなく実用的な感じがします……でしょうか……?
こんな感じで似たようなスレッド作るときこそクラスとかを使うべきなんでしょうけど、オブジェクト指向がよくわからないので冗長になっているかもしれません。

おわりに

Pythonで非同期処理やってOSC送るなんていうニッチなことをする人が自分以外にいらっしゃるのかはわかりませんが、もしかしたらいるかも……ということで今回やってみました。
うまくやるとリズムマシーンみたいなものも作れるので案外楽しいです。

関連記事

python-oscを使ってみる:後編

python-oscを使ってみる:前編

未経験大学生によるPython入門日誌-第2話

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

Yuki.K

1995年生まれ。慶應SFCを2018年3月に卒業予定(予定) 夢も希望もなくキャンパスを彷徨っていたところ、夢と希望いっぱいのBPS村に引きずり込まれてしまった大学生アルバイト。 雑用担当

Yuki.Kの書いた記事

関連する記事

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ