9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TouchDesignerAdvent Calendar 2021

Day 23

TouchDesignerでasyncioを使った非同期処理について

Last updated at Posted at 2021-12-22

こんにちは。ちょうど今年の2月までは制作会社でTouchDeisgnerやUnity,UE4などのコンテンツ制作をしておりました。フリーランスになってからTouchDeisgnerの仕事をする機会は減りましたが、去年に引き続き今年も何か投稿しようということで、以前にTouchDesigner forumで投稿したasyncioの使い方について説明したいと思います。思いのほかフォーラムでレスポンスをいただいたのでみなさんのお役に立てればと思います。

はじめに

TouchDesignerはシングルスレッドで動作するため、待機処理やI/Oバウンドな処理をpythonで実行するとTouchDesignerのプロセスは停止します。

次のようなコードを Textport または text DAT で実行してみると、指定秒数が経過するまでTouchDesignerは停止します。

import time
time.sleep(1)

HTTPによるPOSTも同様に処理が完了するまでTouchDesignerは停止したままです。

import requests
requests.post('<https://derivative.ca/>')

TouchDesignerのオペレーターにはtimer CHOPやWeb DATのような便利な機能がいくつかありますが、これらの機能をPythonで実現するためには非同期処理が必要になります。

マルチスレッドによる非同期処理

Pythonでマルチスレッドというとthreading, concurrent.futures, asyncioといったライブラリがあります。中でもasyncioはシングルスレッドで動作するためTouchDesignerとの連携が簡単です。(一概にthreadingやconcurrent.futuresが適していないという訳ではないです)

ということで次のようなコードを実行したところまんまとTouchDesignerがフリーズしました..

import time
import asyncio

async def test():
    await asyncio.sleep(1)
    print('hello world')

asyncio.run(test())

どうやらはasyncio.run()を実行すると内部的ではrun_until_complete()を呼び出しており、asyncioのイベントループは実行された処理が完了するまでブロックするようです。

そこでloop_create_task()からTaskを生成し、call_soon(event_loop.stop())run_forever()を毎フレーム実行することで、「フレーム毎にイベントループを起動してちょっと仕事したら停止する」みたいに繰り返すことでブロックを回避できるようです。。

(このあたりの説明はわからなくても使えます)

TDAsyncIO.tox

ということでそれらをまとめてtoxにしたものがこれです。

https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/216025/93434375-9d11-34c3-a0cb-781d695bcc39.png

使い方は簡単でこんな感じです

import asyncio

async def test():
    await asyncio.sleep(3)
    print('hello world')

# Run coroutine
coroutines = [test()]
op.TDAsyncIO.Run(coroutines)

# Cancel all tasks
op.TDAsyncIO.Cancel()

グローバルショートカットを設定しているのでop.TDAsyncIOからメソッドを呼べます。

  • op.TDAsyncIO.Run()の引数にコルーチンのリストを渡すだけです。
  • op.TDAsyncIO.Cancel()からすべてのタスクを停止します。

githubのtest.toeにはその他の使い方(subprocessやrequestsと合わせて使う方法)についても簡単なサンプルを置いてあります。
ぜひサーバーと連携する際などは試しに使ってもらえればと思います。

まとめ

  • TouchDesignerのプロセスを停止することなくasyncioが実行できるtoxを作りました
  • サーバーとの連携が必要な処理を実行したいときに便利です
  • メインスレッドで実行されているためtd Moduleを使えます

ちなみに非同期処理と記載がありますがasyncioではCPUバウンドな処理を高速化することは期待できません。CPUバウンドな処理についてはEngine COMP刻みTD などのようにプロセスを分離することを推奨します。

9
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?