Notes 🇯🇵#

AsyncKivyにおける入出力#

asynckivy はtrioやasyncioのような入出力機能を持たないのでGUIを固まらせずにそれをしたければ別のスレッドで行うのが良いと思います。 今のところ関数を別のスレッドで実行する方法には次の二つの方法があります。

from concurrent.futures import ThreadPoolExecutor
import asynckivy as ak

executor = ThreadPoolExecutor()

async def async_func():
    # 方法その一
    # 新しくthreadを作ってそこで渡された関数を実行し、その完了を待つ
    r = await ak.run_in_thread(外部のスレッドで実行させたい関数)
    print("return value:", r)

    # 方法そのニ
    # ThreadPoolExecutor内で渡された関数を実行し、その完了を待つ
    r = await ak.run_in_executor(executor, 外部のスレッドで実行させたい関数)
    print("return value:", r)

スレッド内で起きた例外(ExceptionではないBaseExceptionは除く)は呼び出し元に運ばれるので、 以下のように通常の同期コードを書く感覚で例外を捌けます。

import requests
import asynckivy as ak

async def async_func(label):
    try:
        response = await ak.run_in_thread(lambda: requests.get('htt...', timeout=10))
    except requests.Timeout:
        label.text = "制限時間内に応答無し"
    else:
        label.text = "応答有り: " + response.text

Asyncジェネレータが抱える問題#

asynciotrio がasyncジェネレータに対して 付け焼き刃的な処置 を行うせいなのか、asynckivy用のasyncジェネレータがうまく機能しない事があります。 なので asyncio 或いは trio を使っている場合は以下のAPI達を使わなのがお薦めです。

  • rest_of_touch_events() (代わりに watch_touch を用いる)

  • anim_with_xxx (代わりに repeat_sleeping を用いる)

  • interpolate (代わりに repeat_sleeping を用いる)

  • fade_transition()

これにどう対処すればいいのかは現状分かっていません。 もしかすると PEP 533 が解決してくれるかも。

async操作が禁じられている場所#

asynckivy のAPIでasyncイテレータを返す物のほとんどはその繰り返し中にasync操作を行うことを認めていません。 以下が該当する者たちです。

async for __ in rest_of_touch_events(...):
    await awaitable  # 駄目
    async with async_context_manager:  # 駄目
        ...
    async for __ in async_iterator:  # 駄目
        ...

アニメーションは時間内に終わるとは限らない#

全てのアニメーション関連のAPIは指定された時間内に終わることを保証しません。 これは step 引数が十分に小さい限りは特に気にしなくて良い事なのですが そうではない場合に何が起こるのか把握しておいてください。

async for dt, et, p in anim_with_dt_et_ratio(duration=2.0, step=0.6):
    print(dt, et, p)

dt

et

p

0.6

0.6

0.3

0.6

1.2

0.6

0.6

1.8

0.9

0.6

2.4

1.2

最終行を見て分かるように et の値が大幅に duration 引数を上回っていますし、 p の値も大幅に 1.0 を上回っています。 もし厳密に時間内に終わらせたいなら、コードブロックを asynckivy.move_on_after() で包んで下さい。

async with move_on_after(2.0):
    async for dt, et, p in anim_with_dt_et_progress(duration=2.0, step=0.6):
        print(dt, et, p)

dt

et

p

0.6

0.6

0.3

0.6

1.2

0.6

0.6

1.8

0.9