fzyzcjy / flutter_rust_bridge

Flutter/Dart <-> Rust binding generator, feature-rich, but seamless and simple.
https://fzyzcjy.github.io/flutter_rust_bridge/
MIT License
4.09k stars 278 forks source link

Flutter<->Rust thread communication to improve performance #631

Closed vincent-herlemont closed 1 year ago

vincent-herlemont commented 2 years ago

Is your feature request related to a problem?

Context: The rust part use an embedded database spacejam/sled. Goal: Avoid init the database for each call to the Rust code.

Currently, I haven't found any other solutions unless to init the contexts (databases etc.) to each call to the Rust code. Plus, in my issue, I need to set up a queue with dart-isolate to avoid file access conflicts. That is CPU time-consuming, limited concurrency offered by rust, and increases the code complexity.

Describe the solution you'd like It should developer friendly to create a dedicated "Rust" thread and communicate with it directly with the dart as we can do with dart-isolate in Dart or channel std/sync/mpsc in Rust.

sequenceDiagram
    Flutter->>+Rust: Spawn thread.
    Note right of Rust: Heavy computation.
    Flutter->>Rust: .send('message')
    Rust->>Flutter: .send('message')
    Rust-->>-Flutter: Close thread

Additional context

welcome[bot] commented 2 years ago

Hi! Thanks for opening your first issue here! :smile:

fzyzcjy commented 2 years ago

I haven't found any other solutions unless to init the contexts (databases etc.) to each call to the Rust code.

http://cjycode.com/flutter_rust_bridge/feature/init.html

vincent-herlemont commented 2 years ago

@fzyzcjy Thank you for your answer. You put me on the way.

My apologies, I had misunderstood the architecture of the library. From what I understand, the rust code is called once and runs all the time in the background. This means that I can easily use once_cell to store states in rust and it should be available for all subsequent calls. In this case no need of FlutterRustBridgeSetupMixin.

I test the following code and that works with success.

// api.rs
use flutter_rust_bridge::*;
use std::sync::Mutex;
use once_cell::sync::Lazy;

static DB: Lazy<Mutex<Option<sled::Db>>> = Lazy::new(|| {
    Mutex::new(None)
});

pub fn db_setup(db_path: String) {
    let mut db = DB.lock().unwrap();
    let sled_db = sled::open(&db_path).unwrap();
    *db = Some(sled_db);
}

pub fn insert(key: String, value: String) {
    let mut db = DB.lock().unwrap();
    if let Some(db) = &mut *db {
        db.insert(key.as_str(),value.as_str()).unwrap();
    }
}
// main.dart
void main() async {
  ...
  await api.dbSetup(dbPath: dir.path);
}

// others place
await api.insert(key,value);

Some questions:

fzyzcjy commented 2 years ago

You are welcome.

Is there a risk that static DB should be dropped during flutter program execution?

I have not seen that case in my own app in production. Theoretically IMHO also no risk.

This way of doing seems to you good use of flutter_rust_bridge or do I miss some things?

LGTM. You can also use the setup function in the link I provide, but init in main is even easier to understand so looks completely ok

github-actions[bot] commented 1 year ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new issue.