VOICEVOXを雑に多重動作させる@m1 mac

https://qiita.com/uezo/items/7e476147ec6312ad8a2c
でどうなんでしょ？
と思ってソースコード確認した。

私の案は
「雑にengineをqueueに入れて多数作って使いまわせば良いのでは？」
githubではものすごい深淵な議論がなされており、理解できなかった。

で、ソースを見たらpythonファイルでuvicornが起動していた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/6e3e5207-147a-f57a-c9e1-155809e42100.png)

AIに聞いたらデフォルトだと1ワーカーだそうで。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/9aee920e-5579-3816-1500-7a5457cac2ee.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/42288dd5-34e3-b3e7-01a4-a68e2fcfdf95.png)
gunicornで動かしましょうか。

また、メソッドが`async def`ではなく`def`で定義されてた。AIに聞いたらasyncにしよ？って言われた
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/9bb2ada1-ddf7-575c-b99f-8c11020ac2e4.png)


# やったこと
- 引数ベースを引っぺがし
gunicornで動かしたかったので引数ベースで動いていたところを雑にひっぺがした。
誰か賢い人が.envとかを見るようにしてくれると思う。

- queueにengineをいっぱい突っ込み。メモリ状況とか知らん
```python
shared_engines = asyncio.Queue()
async def enqueue():
    await shared_engines.put(
        make_synthesis_engines(
            use_gpu=False,
            #            voicelib_dirs=args.voicelib_dir,
            voicevox_dir="./voicevox_core",
            #                voicevox_dir=args.voicevox_dir,
            #            runtime_dirs=args.runtime_dir,
            cpu_num_threads=4,
            #            enable_mock=args.enable_mock,
            #            load_all_models=args.load_all_models,
        )
    )


async def a():
    tasks = [enqueue() for i in range(20)]
    await asyncio.gather(*tasks)

asyncio.run(a())

```

- synthesizeをqueueから引っ張り出して処理して返す
知らんけどqueueがうまい感じにしてくれるらしい。
 
```python
    async def synthesis( 
        query: AudioQuery,
        speaker: int,
        enable_interrogative_upspeak: bool = Query(  # noqa: B008
            default=True,
            description="疑問系のテキストが与えられたら語尾を自動調整する",
        ),
        core_version: Optional[str] = None,
    ):
        # engine = get_engine(core_version)
        _engine: Dict = await shared_engines.get() # とって
        engine = _engine[latest_core_version]
        wave = engine.synthesis( 
            query=query,
            speaker_id=speaker,
            enable_interrogative_upspeak=enable_interrogative_upspeak,
        ) # 処理して
        await shared_engines.put(_engine) # 返す
        with NamedTemporaryFile(delete=False) as f:
            soundfile.write(
                file=f, data=wave, samplerate=query.outputSamplingRate, format="WAV"
            )

        return FileResponse(
            f.name,
            media_type="audio/wav",
            background=BackgroundTask(delete_file, f.name),
        )

``` 

- gunicornでぶん回し
```bash
DYLD_LIBRARY_PATH="./voicevox_core" ./venv/bin/gunicorn  -w 4 -k uvicorn.workers.UvicornWorker -t 2 run:app -b 0.0.0.0:50021   
```

# 結果
速くなったんじゃね？
多分罠もあるけど、それは使い込んでいくうちにわかるでしょう。
```
(venv) seijiro%@MBP2021 23-04-17 1:34  ~/Downloads/VOICEVOX
> python3 a.py
total: 9.5367431640625e-07
[0] start
[1] start
[2] start
[3] start
[4] start
[5] start
[6] start
[7] start
[8] start
[9] start
[10] start
[11] start
[12] start
[13] start
[1] 0.11768007278442383
[14] start
[5] 0.11766815185546875
[15] start
[8] 0.11812782287597656
[16] start
[16] 0.1062307357788086
[17] start
[14] 0.20920181274414062
[18] start
[15] 0.2092149257659912
[19] start
[17] 0.10631299018859863
[20] start
[20] 0.10648393630981445
[21] start
[18] 0.11180329322814941
[19] 0.11126995086669922
[22] start
[23] start
[21] 0.10947203636169434
[22] 0.10852193832397461
[24] start
[25] start
[23] 0.10919809341430664
[26] start
[24] 0.10763907432556152
[27] start
[26] 0.10695338249206543
[28] start
[25] 0.10792398452758789
[29] start
[28] 0.1062309741973877
[30] start
[27] 0.2104179859161377
[29] 0.20941781997680664
[31] start
[32] start
[30] 0.20685100555419922
[33] start
[31] 0.10732793807983398
[34] start
[32] 0.20833086967468262
[35] start
[34] 0.10609889030456543
[36] start
[2] 1.1471049785614014
[37] start
[7] 1.1470868587493896
[38] start
[10] 1.1468992233276367
[39] start
[13] 1.1438801288604736
[0] 1.149369239807129
[40] start
[41] start
[3] 1.1501047611236572
[42] start
[11] 1.1491000652313232
[9] 1.150317907333374
[43] start
[6] 1.1511962413787842
[44] start
[4] 1.151780128479004
[12] 1.1481330394744873
[46] start
[47] start
[45] start
[36] 0.1063389778137207
[48] start
[38] 0.10959577560424805
[49] start
[48] 0.10564017295837402
[50] start
[39] 0.21235918998718262
[51] start
[37] 0.2141737937927246
[52] start
[50] 0.10611891746520996
[53] start
[49] 0.20754384994506836
[54] start
[51] 0.10854601860046387
[55] start
[53] 0.10693502426147461
[56] start
[52] 0.2092580795288086
[57] start
[54] 0.10974597930908203
[58] start
[56] 0.10783910751342773
[59] start
[55] 0.21094322204589844
[60] start
[57] 0.11180973052978516
[61] start
[59] 0.11128401756286621
[62] start
[58] 0.21242594718933105
[63] start
[60] 0.11000394821166992
[61] 0.10776591300964355
[64] start
[65] start
[62] 0.1063530445098877
[66] start
[63] 0.10947990417480469
[67] start
[66] 0.10582184791564941
[68] start
[33] 1.0093669891357422
[69] start
[64] 0.2096881866455078
[65] 0.20943474769592285
[70] start
[71] start
[68] 0.10678505897521973
[72] start
[35] 1.0282468795776367
[73] start
[47] 0.9496421813964844
[42] 0.9546129703521729
[74] start
[75] start
[46] 0.9510161876678467
[41] 0.9562287330627441
[43] 0.9537999629974365
[40] 0.9565579891204834
[67] 0.20866703987121582
[44] 0.9528160095214844
[76] start
[77] start
[45] 0.9523530006408691
[81] start
[80] start
[82] start
[78] start
[79] start
[70] 0.20840191841125488
[83] start
[69] 0.23237395286560059
[84] start
[71] 0.21073412895202637
[85] start
[73] 0.20993995666503906
[86] start
[75] 0.21073675155639648
[87] start
[74] 0.21256208419799805
[88] start
[83] 0.21004605293273926
[89] start
[84] 0.21010112762451172
[90] start
[86] 0.11104226112365723
[91] start
[85] 0.315673828125
[92] start
[88] 0.212385892868042
[93] start
[90] 0.11255502700805664
[94] start
[87] 0.3148622512817383
[95] start
[91] 0.20917105674743652
[96] start
[89] 0.21555805206298828
[97] start
[92] 0.21069788932800293
[98] start
[93] 0.2091519832611084
[99] start
[94] 0.2107250690460205
[95] 0.11324095726013184
[96] 0.2097017765045166
[97] 0.21002483367919922
[98] 0.1088099479675293
[99] 0.1085357666015625
[72] 0.8197391033172607
[80] 0.753695011138916
[82] 0.7533178329467773
[76] 0.7561259269714355
[78] 0.7531208992004395
[81] 0.7553017139434814
[77] 0.7571148872375488
[79] 0.7542757987976074
total: 2.867227077484131
```

この辺のログの感じで並列な感じで動いていると考えても良いのではないでしょうか？
```
[0] start
[1] start
[2] start
[3] start
[4] start
[5] start
[6] start
[7] start
[8] start
[9] start
[10] start
[11] start
[12] start
[13] start
[1] 0.11768007278442383 #ほぼ一緒
[14] start
[5] 0.11766815185546875 #ほぼ一緒


```

一応wavに落としてちゃんtの再生できるかもかくにんしましたが大丈夫そう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/45012197-c2fb-5b04-3f39-76a4f39abf59.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/55774f4c-2fdb-3f64-a830-57cf9437f995.png)

良い感じにそこそこコアを使い切ってる感じもあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/306d0bac-049e-9cb8-6611-02a0a8961f01.png)


# ハマったところ
python-soundfileが使っているcffiがm1macで死んだので
https://github.com/bastibe/python-soundfile/issues/325
を参考にした。
python-soundfileが転けたのでモンキーも施した。
pullリクすべきですね。知らんけど。暇を見つけてプルリクします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/13106/98bd08dc-95b7-0043-4da9-4dd9841e5bbe.png)


## pullリクについて
なんか現場はm1macのバージョンはwhlを用意して捨て置かれているようなので下記モンキーパッチにしました
```python
from soundfile import _default_subtypes
def my_default_subtype(format):
    return _default_subtypes.get(format)


soundfile.default_subtype = my_default_subtype
```