Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change: Rust APIの脱Tokioと、voicevox_core::{tokiononblocking} #831

Merged
merged 1 commit into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ async-fs = "2.1.2"
async_zip = "=0.0.16"
bindgen = "0.69.4"
binstall-tar = "0.4.39"
blocking = "1.6.1"
bytes = "1.1.0"
camino = "1.1.6"
cargo_metadata = "0.18.1"
Expand Down Expand Up @@ -57,6 +58,7 @@ octocrab = { version = "0.19.0", default-features = false }
once_cell = "1.19.0"
ouroboros = "0.18.0"
parse-display = "0.8.2"
pollster = "0.3.0"
pretty_assertions = "1.3.0"
proc-macro2 = "1.0.69"
pyo3 = "0.20.3"
Expand Down
5 changes: 3 additions & 2 deletions crates/voicevox_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ link-onnxruntime = []
anyhow.workspace = true
async-fs.workspace = true
async_zip = { workspace = true, features = ["deflate"] }
blocking.workspace = true
camino.workspace = true
const_format.workspace = true
derive-getters.workspace = true
Expand All @@ -27,7 +28,7 @@ duplicate.workspace = true
easy-ext.workspace = true
educe.workspace = true
enum-map.workspace = true
fs-err = { workspace = true, features = ["tokio"] }
fs-err.workspace = true
futures-io.workspace = true
futures-lite.workspace = true
futures-util = { workspace = true, features = ["io"] }
Expand All @@ -46,14 +47,14 @@ smallvec.workspace = true
strum = { workspace = true, features = ["derive"] }
tempfile.workspace = true
thiserror.workspace = true
tokio = { workspace = true, features = ["rt"] } # FIXME: feature-gateする
tracing.workspace = true
uuid = { workspace = true, features = ["v4", "serde"] }
voicevox-ort = { workspace = true, features = ["download-binaries", "__init-for-voicevox"] }
voicevox_core_macros = { path = "../voicevox_core_macros" }

[dev-dependencies]
heck.workspace = true
pollster = { workspace = true, features = ["macro"] }
pretty_assertions.workspace = true
rstest.workspace = true
rstest_reuse.workspace = true
Expand Down
12 changes: 6 additions & 6 deletions crates/voicevox_core/src/__internal/doctest_fixtures.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,23 @@ pub async fn synthesizer_with_sample_voice_model(
OsString,
>,
open_jtalk_dic_dir: impl AsRef<Utf8Path>,
) -> anyhow::Result<crate::tokio::Synthesizer<crate::tokio::OpenJtalk>> {
let syntesizer = crate::tokio::Synthesizer::new(
) -> anyhow::Result<crate::nonblocking::Synthesizer<crate::nonblocking::OpenJtalk>> {
let syntesizer = crate::nonblocking::Synthesizer::new(
#[cfg(feature = "load-onnxruntime")]
crate::tokio::Onnxruntime::load_once()
crate::nonblocking::Onnxruntime::load_once()
.filename(onnxruntime_dylib_path)
.exec()
.await?,
#[cfg(feature = "link-onnxruntime")]
crate::tokio::Onnxruntime::init_once().await?,
crate::tokio::OpenJtalk::new(open_jtalk_dic_dir).await?,
crate::nonblocking::Onnxruntime::init_once().await?,
crate::nonblocking::OpenJtalk::new(open_jtalk_dic_dir).await?,
&InitializeOptions {
acceleration_mode: AccelerationMode::Cpu,
..Default::default()
},
)?;

let model = &crate::tokio::VoiceModel::from_path(voice_model_path).await?;
let model = &crate::nonblocking::VoiceModel::from_path(voice_model_path).await?;
syntesizer.load_voice_model(model).await?;

Ok(syntesizer)
Expand Down
6 changes: 2 additions & 4 deletions crates/voicevox_core/src/asyncs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
//! に[`SingleTasked`]を用意している。
//!
//! [ブロッキング版API]: crate::blocking
//! [非同期版API]: crate::tokio
//! [blocking]: https://docs.rs/crate/blocking
//! [非同期版API]: crate::nonblocking

use std::{
io::{self, Read as _, Seek as _, SeekFrom},
Expand Down Expand Up @@ -71,8 +70,7 @@ impl Async for SingleTasked {
///
/// [非同期版API]用。
///
/// [blocking]: https://docs.rs/crate/blocking
/// [非同期版API]: crate::tokio
/// [非同期版API]: crate::nonblocking
pub(crate) enum BlockingThreadPool {}

impl Async for BlockingThreadPool {
Expand Down
4 changes: 2 additions & 2 deletions crates/voicevox_core/src/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ fn test_gpu(
/// しても`cuda`や`dml`は`true`を示しうる。
///
/// ```
/// # #[tokio::main]
/// # #[pollster::main]
/// # async fn main() -> anyhow::Result<()> {
/// use voicevox_core::{tokio::Onnxruntime, SupportedDevices};
/// use voicevox_core::{nonblocking::Onnxruntime, SupportedDevices};
///
/// # voicevox_core::blocking::Onnxruntime::load_once()
/// # .filename(if cfg!(windows) {
Expand Down
4 changes: 2 additions & 2 deletions crates/voicevox_core/src/engine/full_context_label.rs
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ mod tests {
#[apply(label_cases)]
#[tokio::test]
async fn open_jtalk(text: &str, labels: &[&str], _accent_phrase: &[AccentPhrase]) {
let open_jtalk = crate::tokio::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
let open_jtalk = crate::nonblocking::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
.await
.unwrap();
assert_eq!(&open_jtalk.extract_fullcontext(text).unwrap(), labels);
Expand All @@ -447,7 +447,7 @@ mod tests {
#[apply(label_cases)]
#[tokio::test]
async fn extract_fullcontext(text: &str, _labels: &[&str], accent_phrase: &[AccentPhrase]) {
let open_jtalk = crate::tokio::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
let open_jtalk = crate::nonblocking::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
.await
.unwrap();
assert_eq!(
Expand Down
28 changes: 24 additions & 4 deletions crates/voicevox_core/src/engine/open_jtalk.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
// TODO: `VoiceModel`のように、次のような設計にする。
//
// ```
// pub(crate) mod blocking {
// pub struct OpenJtalk(Inner<SingleTasked>);
// // …
// }
// pub(crate) mod nonblocking {
// pub struct OpenJtalk(Inner<BlockingThreadPool>);
// // …
// }
// ```

use ::open_jtalk::Text2MecabError;

#[derive(thiserror::Error, Debug)]
Expand Down Expand Up @@ -183,12 +196,19 @@ pub(crate) mod blocking {
}
}

pub(crate) mod tokio {
pub(crate) mod nonblocking {
use camino::Utf8Path;

use super::FullcontextExtractor;

/// テキスト解析器としてのOpen JTalk。
///
/// # Performance
///
/// [blocking]クレートにより動いている。詳しくは[`nonblocking`モジュールのドキュメント]を参照。
///
/// [blocking]: https://docs.rs/crate/blocking
/// [`nonblocking`モジュールのドキュメント]: crate::nonblocking
#[derive(Clone)]
pub struct OpenJtalk(super::blocking::OpenJtalk);

Expand All @@ -206,7 +226,7 @@ pub(crate) mod tokio {
/// この関数を呼び出した後にユーザー辞書を変更した場合は、再度この関数を呼ぶ必要がある。
pub async fn use_user_dict(
&self,
user_dict: &crate::tokio::UserDict,
user_dict: &crate::nonblocking::UserDict,
) -> crate::result::Result<()> {
let inner = self.0 .0.clone();
let words = user_dict.to_mecab_format();
Expand Down Expand Up @@ -325,7 +345,7 @@ mod tests {
#[case] text: &str,
#[case] expected: anyhow::Result<Vec<String>>,
) {
let open_jtalk = super::tokio::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
let open_jtalk = super::nonblocking::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
.await
.unwrap();
let result = open_jtalk.extract_fullcontext(text);
Expand All @@ -339,7 +359,7 @@ mod tests {
#[case] text: &str,
#[case] expected: anyhow::Result<Vec<String>>,
) {
let open_jtalk = super::tokio::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
let open_jtalk = super::nonblocking::OpenJtalk::new(OPEN_JTALK_DIC_DIR)
.await
.unwrap();
for _ in 0..10 {
Expand Down
38 changes: 28 additions & 10 deletions crates/voicevox_core/src/infer/runtimes/onnxruntime.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,16 @@
// TODO: `VoiceModel`のように、次のような設計にする。
//
// ```
// pub(crate) mod blocking {
// pub struct Onnxruntime(Inner<SingleTasked>);
// // …
// }
// pub(crate) mod nonblocking {
// pub struct Onnxruntime(Inner<BlockingThreadPool>);
// // …
// }
// ```

use std::{fmt::Debug, vec};

use anyhow::{anyhow, bail, ensure};
Expand All @@ -18,9 +31,6 @@ use super::super::{
OutputScalarKind, OutputTensor, ParamInfo, PushInputTensor,
};

// TODO: `trait AsyncRuntime`みたいなものを作って抽象化しながら同期版と非同期版に別個の役割を
// 持たせる
// (なぜそうしたいかの理由の一つとしては<https://github.com/VOICEVOX/voicevox_core/issues/687>)
impl InferenceRuntime for self::blocking::Onnxruntime {
type Session = ort::Session;
type RunContext<'a> = OnnxruntimeRunContext<'a>;
Expand Down Expand Up @@ -254,7 +264,7 @@ pub(crate) mod blocking {
/// # Rust APIにおけるインスタンスの共有
///
/// インスタンスは[voicevox-ort]側に作られる。Rustのクレートとしてこのライブラリを利用する場合、
/// Tokio版APIやvoicevox-ortを利用する他クレートともインスタンスが共有される。
/// 非同期版APIやvoicevox-ortを利用する他クレートともインスタンスが共有される。
///
#[cfg_attr(feature = "load-onnxruntime", doc = "```")]
#[cfg_attr(not(feature = "load-onnxruntime"), doc = "```compile_fail")]
Expand All @@ -268,7 +278,7 @@ pub(crate) mod blocking {
/// # .exec()?;
/// # }
/// let ort1 = voicevox_core::blocking::Onnxruntime::load_once().exec()?;
/// let ort2 = another_lib::tokio::Onnxruntime::get().expect("`ort1`と同一のはず");
/// let ort2 = another_lib::nonblocking::Onnxruntime::get().expect("`ort1`と同一のはず");
/// assert_eq!(ptr_addr(ort1), ptr_addr(ort2));
///
/// fn ptr_addr(obj: &impl Sized) -> usize {
Expand Down Expand Up @@ -430,7 +440,7 @@ pub(crate) mod blocking {
}
}

pub(crate) mod tokio {
pub(crate) mod nonblocking {
use ref_cast::{ref_cast_custom, RefCastCustom};

use crate::SupportedDevices;
Expand All @@ -448,15 +458,17 @@ pub(crate) mod tokio {
#[cfg_attr(not(feature = "load-onnxruntime"), doc = "```compile_fail")]
/// # use voicevox_core as another_lib;
/// #
/// # #[tokio::main]
/// # #[pollster::main]
/// # async fn main() -> anyhow::Result<()> {
/// # if cfg!(windows) {
/// # // Windows\System32\onnxruntime.dllを回避
/// # voicevox_core::blocking::Onnxruntime::load_once()
/// # .filename(test_util::ONNXRUNTIME_DYLIB_PATH)
/// # .exec()?;
/// # }
/// let ort1 = voicevox_core::tokio::Onnxruntime::load_once().exec().await?;
/// let ort1 = voicevox_core::nonblocking::Onnxruntime::load_once()
/// .exec()
/// .await?;
/// let ort2 = another_lib::blocking::Onnxruntime::get().expect("`ort1`と同一のはず");
/// assert_eq!(ptr_addr(ort1), ptr_addr(ort2));
///
Expand All @@ -467,7 +479,13 @@ pub(crate) mod tokio {
/// # }
/// ```
///
/// # Performance
///
/// [blocking]クレートにより動いている。詳しくは[`nonblocking`モジュールのドキュメント]を参照。
///
/// [voicevox-ort]: https://github.com/VOICEVOX/ort
/// [blocking]: https://docs.rs/crate/blocking
/// [`nonblocking`モジュールのドキュメント]: crate::nonblocking
#[derive(Debug, RefCastCustom)]
#[repr(transparent)]
pub struct Onnxruntime(pub(crate) super::blocking::Onnxruntime);
Expand Down Expand Up @@ -584,11 +602,11 @@ mod tests {

assert_eq!(
super::blocking::Onnxruntime::LIB_NAME,
super::tokio::Onnxruntime::LIB_NAME,
super::nonblocking::Onnxruntime::LIB_NAME,
);
assert_eq!(
super::blocking::Onnxruntime::LIB_VERSION,
super::tokio::Onnxruntime::LIB_VERSION,
super::nonblocking::Onnxruntime::LIB_VERSION,
);
}

Expand Down
2 changes: 1 addition & 1 deletion crates/voicevox_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ mod voice_model;

pub mod __internal;
pub mod blocking;
pub mod tokio;
pub mod nonblocking;

#[cfg(test)]
mod test_util;
Expand Down
25 changes: 25 additions & 0 deletions crates/voicevox_core/src/nonblocking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//! 非同期版API。
//!
//! # Performance
//!
//! これらは[blocking]クレートにより動いている。特定の非同期ランタイムを必要とせず、[pollster]など
//! でも動かすことができる。
Comment on lines +5 to +6
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

・・・・・・・あれ、これどういうことでしたっけ。。。

blokingモジュール(クレート)があって、これはAsyncを実装してくれてる感じ・・・?
(プレーンなRustのasyncは非同期の機能がなく、非同期用のクレートを使わないと非同期にできない、という理解でいます)

blocking、名前めちゃくちゃややこしいですね・・・。

Copy link
Member Author

@qryxip qryxip Sep 13, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

そうですね。こんな感じです。

  • blocking: 外部ライブラリ名。VOICEVOX COREのパブリックAPIとしてはドキュメントのみ登場
  • voicevox_core::blocking: パブリックAPIの一部
  • voicevox_core::nonblocking: パブリックAPIの一部。内部でblocking(外部ライブラリ名)を使っている

blocking、名前めちゃくちゃややこしいですね・・・。

ですね。

前身としてunblockという、unblock::unblock(…)という形で使えるクレートがあって更新が途絶えているのですが、よく見たらこれblockingよりに誕生したものですね。なんでこの名前にしなかったんだろう…

2回くらい言ったかもしれませんが、せめてリポジトリ名(smol-rs/blocking)がblocking-rsとかだったらそっちで呼べるのに…

//!
//! スレッドプールおよびエグゼキュータはblockingクレートに依存するすべてのプログラム間で共有される。
//! スレッドプールのサイズは、blockingクレートの説明にある通り`$BLOCKING_MAX_THREADS`で調整すること
//! ができる。
//!
//! [blocking]: https://docs.rs/crate/blocking
//! [pollster]: https://docs.rs/crate/pollster

pub use crate::{
engine::open_jtalk::nonblocking::OpenJtalk,
infer::runtimes::onnxruntime::nonblocking::Onnxruntime, synthesizer::nonblocking::Synthesizer,
user_dict::dict::nonblocking::UserDict, voice_model::nonblocking::VoiceModel,
};

pub mod onnxruntime {
#[cfg(feature = "load-onnxruntime")]
#[cfg_attr(docsrs, doc(cfg(feature = "load-onnxruntime")))]
pub use crate::infer::runtimes::onnxruntime::nonblocking::LoadOnce;
}
4 changes: 2 additions & 2 deletions crates/voicevox_core/src/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,7 @@ mod tests {
talk: enum_map!(_ => InferenceSessionOptions::new(0, DeviceSpec::Cpu)),
},
);
let model = &crate::tokio::VoiceModel::sample().await.unwrap();
let model = &crate::nonblocking::VoiceModel::sample().await.unwrap();
let model_contents = &model.read_inference_models().await.unwrap();
let result = status.insert_model(model.header(), model_contents);
assert_debug_fmt_eq!(Ok(()), result);
Expand All @@ -424,7 +424,7 @@ mod tests {
talk: enum_map!(_ => InferenceSessionOptions::new(0, DeviceSpec::Cpu)),
},
);
let vvm = &crate::tokio::VoiceModel::sample().await.unwrap();
let vvm = &crate::nonblocking::VoiceModel::sample().await.unwrap();
let model_header = vvm.header();
let model_contents = &vvm.read_inference_models().await.unwrap();
assert!(
Expand Down
Loading
Loading