├── .env ├── .github └── workflows │ ├── publish.yml │ └── rust.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.toml ├── LICENSE ├── README.md ├── benches └── bench.rs ├── examples ├── nums.rs ├── nums_rw.rs ├── table.sql ├── test_sqlx.rs └── test_sqlx_rw_model.rs ├── rustfmt.toml ├── src ├── actor.rs ├── inner_store.rs ├── lib.rs ├── mutex │ ├── item.rs │ └── mod.rs ├── pc_model.rs ├── rw_model.rs ├── rwlock │ └── mod.rs └── semaphore │ └── mod.rs └── tests ├── test.rs ├── test_rw.rs └── test_semaphore.rs /.env: -------------------------------------------------------------------------------- 1 | DATABASE_URL="sqlite://:memory:" -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Crates 2 | 3 | 4 | on: 5 | push: 6 | tags: 7 | - v[0-9]+.* 8 | 9 | env: 10 | CARGO_INCREMENTAL: 0 11 | CARGO_NET_GIT_FETCH_WITH_CLI: true 12 | CARGO_NET_RETRY: 10 13 | CARGO_TERM_COLOR: always 14 | RUST_BACKTRACE: 1 15 | RUSTFLAGS: -D warnings 16 | RUSTUP_MAX_RETRIES: 10 17 | 18 | defaults: 19 | run: 20 | shell: bash 21 | 22 | jobs: 23 | create-release: 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@v3 27 | with: 28 | persist-credentials: false 29 | - name: Install Rust 30 | run: rustup update stable --no-self-update 31 | - uses: taiki-e/create-gh-release-action@v1 32 | with: 33 | changelog: "CHANGELOG.md" 34 | title: "aqueue $version" 35 | branch: master 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | - uses: Swatinem/rust-cache@v2 39 | - run: cargo publish 40 | env: 41 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 42 | 43 | -------------------------------------------------------------------------------- /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | # Disable incremental compilation. 12 | # 13 | # Incremental compilation is useful as part of an edit-build-test-edit cycle, 14 | # as it lets the compiler avoid recompiling code that hasn't changed. However, 15 | # on CI, we're not making small edits; we're almost always building the entire 16 | # project from scratch. Thus, incremental compilation on CI actually 17 | # introduces *additional* overhead to support making future builds 18 | # faster...but no future builds will ever occur in any given CI environment. 19 | # 20 | # See https://matklad.github.io/2021/09/04/fast-rust-builds.html#ci-workflow 21 | # for details. 22 | CARGO_INCREMENTAL: 0 23 | # Allow more retries for network requests in cargo (downloading crates) and 24 | # rustup (installing toolchains). This should help to reduce flaky CI failures 25 | # from transient network timeouts or other issues. 26 | CARGO_NET_RETRY: 10 27 | RUSTUP_MAX_RETRIES: 10 28 | RUST_BACKTRACE: 1 29 | 30 | jobs: 31 | check: 32 | name: Check 33 | runs-on: ubuntu-latest 34 | steps: 35 | - name: Checkout sources 36 | uses: actions/checkout@v3 37 | - uses: Swatinem/rust-cache@v2 38 | 39 | - name: Run cargo check 40 | run: cargo check 41 | 42 | test: 43 | name: test 44 | runs-on: ubuntu-latest 45 | steps: 46 | - name: Test sources 47 | uses: actions/checkout@v3 48 | - uses: Swatinem/rust-cache@v2 49 | 50 | - name: Run cargo test 51 | run: cargo test --features tokio_time 52 | 53 | lints: 54 | name: Lints 55 | runs-on: ubuntu-latest 56 | steps: 57 | - name: Checkout sources 58 | uses: actions/checkout@v3 59 | - uses: Swatinem/rust-cache@v2 60 | 61 | - name: Run cargo fmt 62 | run: cargo fmt --all -- --check 63 | 64 | - name: Run cargo clippy 65 | run: cargo clippy -- -D warnings 66 | 67 | 68 | test_os: 69 | name: Build on ${{ matrix.os }} with Rust ${{ matrix.rust }} 70 | runs-on: ${{ matrix.os }} 71 | strategy: 72 | fail-fast: false 73 | matrix: 74 | os: [ubuntu-latest, macos-latest, windows-latest] 75 | rust: [stable] 76 | include: 77 | - rust: nightly 78 | os: ubuntu-latest 79 | steps: 80 | - name: Checkout sources 81 | uses: actions/checkout@v3 82 | 83 | - name: Install ${{ matrix.rust }} toolchain 84 | run: rustup toolchain add ${{ matrix.rust }} --no-self-update && rustup default ${{ matrix.rust }} 85 | - uses: Swatinem/rust-cache@v2 86 | - name: Run cargo build 87 | run: cargo build 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | /target 3 | Cargo.lock -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.4.1 (2024-04-26) 4 | * rename PCModel get_inner() to inner() 5 | 6 | ## 1.4.0 (2024-04-26) 7 | * upgrade async-lock to 3.0 8 | * add PCModel 9 | 10 | ## 1.3.7 (2024-02-01) 11 | * fix queue customized Future Synchronization issues 12 | 13 | ## 1.3.6 (2024-01-18) 14 | * replacement compatible with Rust 1.75 15 | 16 | ## 1.3.5 (2023-08-22) 17 | * fix RwModel call ret ref 18 | 19 | ## 1.3.4 (2023-07-20) 20 | * fix RwModel call_mut ret mut ref 21 | 22 | ## 1.3.3 (2023-07-11) 23 | * upgrade async-lock to 2.7 24 | * modify readme 25 | 26 | ## 1.3.2 (2023-07-04) 27 | * update readme 28 | 29 | ## 1.3.1 (2023-07-03) 30 | * optimize RwModel 31 | * rename mut_call to call_mut 32 | * add macro call_wait and call_mut_wait 33 | 34 | ## 1.3.0 (2023-07-03) 35 | * add RwModel 36 | 37 | ## 1.2.12 (2023-02-20) 38 | #### Features 39 | * test publish [crates.io](https://crates.io/) 2# 40 | 41 | ## 1.2.11 (2023-02-19) 42 | #### Features 43 | * test publish [crates.io](https://crates.io/) 44 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "aqueue" 3 | version = "1.4.1" 4 | authors = ["luyi "] 5 | edition = "2018" 6 | license = "MIT/Apache-2.0" 7 | readme = "README.md" 8 | repository = "https://github.com/luyikk/aqueue" 9 | documentation = "https://docs.rs/aqueue" 10 | description = "fast speed thread safe async execute queue." 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [features] 15 | tokio_time = ["tokio/time"] 16 | async_std_time = ["async-std/unstable"] 17 | 18 | [dependencies] 19 | async-lock = "3.3" 20 | tokio = { version = "1", optional = true } 21 | async-std = { version = "1", optional = true } 22 | 23 | [dev-dependencies] 24 | async-trait = "0.1" 25 | tokio = { version = "1.*", features = ["full"] } 26 | sqlx = { version = "0.7", features = ["sqlite", "runtime-tokio-native-tls"] } 27 | dotenv = "0.15" 28 | lazy_static = "1.4" 29 | criterion = { version = "0.5", features = ["async_tokio"] } 30 | futures-util = "0.3" 31 | anyhow = "1.0" 32 | 33 | [[bench]] 34 | name = "bench" 35 | harness = false -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # fast speed thread safe async execute model 2 | [![Latest Version](https://img.shields.io/crates/v/aqueue.svg)](https://crates.io/crates/aqueue) 3 | [![Rust Documentation](https://img.shields.io/badge/api-rustdoc-blue.svg)](https://docs.rs/aqueue) 4 | [![Rust Report Card](https://rust-reportcard.xuri.me/badge/github.com/luyikk/aqueue)](https://rust-reportcard.xuri.me/report/github.com/luyikk/aqueue) 5 | [![Rust CI](https://github.com/luyikk/aqueue/actions/workflows/rust.yml/badge.svg)](https://github.com/luyikk/aqueue/actions/workflows/rust.yml) 6 | 7 | 8 | ## Example **RwModel** 9 | ### Suitable for situations with more reading and less writing 10 | ```rust 11 | use aqueue::RwModel; 12 | use std::sync::Arc; 13 | use std::time::Instant; 14 | use tokio::try_join; 15 | 16 | #[derive(Default)] 17 | struct Foo { 18 | count: u64, 19 | i: i128, 20 | } 21 | 22 | impl Foo { 23 | pub fn add(&mut self, x: i32) -> i128 { 24 | self.count += 1; 25 | self.i += x as i128; 26 | self.i 27 | } 28 | fn reset(&mut self) { 29 | self.count = 0; 30 | self.i = 0; 31 | } 32 | pub fn get(&self) -> i128 { 33 | self.i 34 | } 35 | pub fn get_count(&self) -> u64 { 36 | self.count 37 | } 38 | } 39 | 40 | 41 | trait FooRunner { 42 | async fn add(&self, x: i32) -> i128; 43 | async fn reset(&self); 44 | async fn get(&self) -> i128; 45 | async fn get_count(&self) -> u64; 46 | } 47 | 48 | impl FooRunner for RwModel { 49 | async fn add(&self, x: i32) -> i128 { 50 | self.call_mut(|mut inner| async move { inner.add(x) }).await 51 | } 52 | async fn reset(&self) { 53 | self.call_mut(|mut inner| async move { inner.reset() }).await 54 | } 55 | async fn get(&self) -> i128 { 56 | self.call(|inner| async move { inner.get() }).await 57 | } 58 | async fn get_count(&self) -> u64 { 59 | self.call(|inner| async move { inner.get_count() }).await 60 | } 61 | } 62 | 63 | #[tokio::main] 64 | async fn main() -> anyhow::Result<()> { 65 | { 66 | // Single thread test 67 | let tf = RwModel::new(Foo::default()); 68 | tf.add(100).await; 69 | assert_eq!(100, tf.get().await); 70 | tf.add(-100).await; 71 | assert_eq!(0, tf.get().await); 72 | tf.reset().await; 73 | 74 | let start = Instant::now(); 75 | for i in 0..100000000 { 76 | tf.add(i).await; 77 | } 78 | 79 | println!( 80 | "test rw a count:{} value:{} time:{} qps:{}", 81 | tf.get_count().await, 82 | tf.get().await, 83 | start.elapsed().as_secs_f32(), 84 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 85 | ); 86 | } 87 | 88 | { 89 | //Multithreading test 90 | let tf = Arc::new(RwModel::new(Foo::default())); 91 | let start = Instant::now(); 92 | let a_tf = tf.clone(); 93 | let a = tokio::spawn(async move { 94 | for i in 0..25000000 { 95 | a_tf.add(i).await; 96 | } 97 | }); 98 | 99 | let b_tf = tf.clone(); 100 | let b = tokio::spawn(async move { 101 | for i in 25000000..50000000 { 102 | b_tf.add(i).await; 103 | } 104 | }); 105 | 106 | let c_tf = tf.clone(); 107 | let c = tokio::spawn(async move { 108 | for i in 50000000..75000000 { 109 | c_tf.add(i).await; 110 | } 111 | }); 112 | 113 | let d_tf = tf.clone(); 114 | let d = tokio::spawn(async move { 115 | for i in 75000000..100000000 { 116 | d_tf.add(i).await; 117 | } 118 | }); 119 | 120 | try_join!(a, b, c, d)?; 121 | 122 | println!( 123 | "test rw b count:{} value:{} time:{} qps:{}", 124 | tf.get_count().await, 125 | tf.get().await, 126 | start.elapsed().as_secs_f32(), 127 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 128 | ); 129 | } 130 | 131 | Ok(()) 132 | } 133 | 134 | ``` 135 | ```shell 136 | test rw a count:100000000 value:4999999950000000 time:5.1791396 qps:19308000 137 | test rw b count:100000000 value:4999999950000000 time:5.293417 qps:18892000 138 | ``` 139 | 140 | ## Example **Actor** Database 141 | ### Suitable for high-performance environments 142 | ### (use Actor Trait and Sqlx Sqlite) 143 | 144 | ```rust 145 | use anyhow::{anyhow, Result}; 146 | use aqueue::{inner_wait, Actor}; 147 | use sqlx::sqlite::SqlitePoolOptions; 148 | use sqlx::SqlitePool; 149 | use std::env; 150 | use tokio::task::JoinHandle; 151 | 152 | #[derive(sqlx::FromRow, Debug)] 153 | #[allow(dead_code)] 154 | pub struct User { 155 | id: i64, 156 | name: String, 157 | gold: f64, 158 | } 159 | 160 | pub struct DataBases { 161 | auto_id: u32, 162 | pool: SqlitePool, 163 | } 164 | 165 | unsafe impl Send for DataBases {} 166 | unsafe impl Sync for DataBases {} 167 | 168 | impl DataBases { 169 | pub fn new(sqlite_max_connections: u32) -> Result> { 170 | let pool = SqlitePoolOptions::new() 171 | .max_connections(sqlite_max_connections) 172 | .connect_lazy("sqlite://:memory:")?; 173 | 174 | Ok(Actor::new(DataBases { auto_id: 0, pool })) 175 | } 176 | /// create user table from table.sql 177 | async fn create_table(&self) -> Result<()> { 178 | sqlx::query(r#" 179 | CREATE TABLE "user" ( 180 | "id" integer NOT NULL PRIMARY KEY, 181 | "name" text, 182 | "gold" real 183 | ); 184 | "#).execute(&self.pool).await?; 185 | Ok(()) 186 | } 187 | /// insert user data 188 | async fn insert_user(&mut self, name: &str, gold: f64) -> Result { 189 | self.auto_id += 1; 190 | let row = sqlx::query( 191 | r#" 192 | insert into `user`(`id`,`name`,`gold`) 193 | values(?,?,?) 194 | "#, 195 | ) 196 | .bind(&self.auto_id) 197 | .bind(name) 198 | .bind(gold) 199 | .execute(&self.pool) 200 | .await? 201 | .rows_affected(); 202 | 203 | Ok(row == 1) 204 | } 205 | /// insert user data 206 | async fn select_all_users(&self) -> Result> { 207 | Ok(sqlx::query_as::<_, User>("select * from `user`").fetch_all(&self.pool).await?) 208 | } 209 | } 210 | 211 | 212 | trait IDatabase { 213 | /// create user table from table.sql 214 | async fn create_table(&self) -> Result<()>; 215 | /// insert user data 216 | async fn insert_user(&self, name: String, gold: f64) -> Result; 217 | /// insert user data 218 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result; 219 | /// select all users table 220 | async fn select_all_users(&self) -> Result>; 221 | } 222 | 223 | impl IDatabase for Actor { 224 | async fn create_table(&self) -> Result<()> { 225 | self.inner_call(|inner| async move { inner.get().create_table().await }).await 226 | } 227 | async fn insert_user(&self, name: String, gold: f64) -> Result { 228 | self.inner_call(|inner| async move { inner.get_mut().insert_user(&name, gold).await }) 229 | .await 230 | } 231 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result { 232 | self.inner_call(|inner| async move { inner.get_mut().insert_user(name, gold).await }) 233 | .await 234 | } 235 | async fn select_all_users(&self) -> Result> { 236 | unsafe { 237 | self.deref_inner().select_all_users().await 238 | } 239 | } 240 | } 241 | 242 | lazy_static::lazy_static! { 243 | /// default global static database actor obj 244 | static ref DB:Actor={ 245 | DataBases::new(50).expect("install db error") 246 | }; 247 | } 248 | 249 | #[tokio::main] 250 | async fn main() -> Result<()> { 251 | 252 | DB.create_table().await?; 253 | let mut join_vec = Vec::with_capacity(100); 254 | // create 100 tokio task run it. 255 | for i in 0..100 { 256 | let join: JoinHandle> = tokio::spawn(async move { 257 | //each task runs 1000 times 258 | for j in 0..1000 { 259 | DB.insert_user(i.to_string(), j as f64).await?; 260 | } 261 | Ok(()) 262 | }); 263 | 264 | join_vec.push(join); 265 | } 266 | //wait all task finish 267 | for join in join_vec { 268 | join.await??; 269 | } 270 | // print all users 271 | for user in DB.select_all_users().await? { 272 | println!("{:?}", user); 273 | } 274 | 275 | Ok(()) 276 | } 277 | 278 | ``` 279 | 280 | ```shell 281 | User { id: 1, name: "0", gold: 0.0 } 282 | User { id: 2, name: "0", gold: 0.0 } 283 | User { id: 3, name: "0", gold: 0.0 } 284 | User { id: 4, name: "10", gold: 0.0 } 285 | User { id: 5, name: "10", gold: 0.0 } 286 | User { id: 6, name: "16", gold: 0.0 } 287 | User { id: 7, name: "10", gold: 0.0 } 288 | ... 289 | User { id: 99996, name: "2", gold: 999.0 } 290 | User { id: 99997, name: "8", gold: 999.0 } 291 | User { id: 99998, name: "5", gold: 999.0 } 292 | User { id: 99999, name: "9", gold: 999.0 } 293 | User { id: 100000, name: "10", gold: 999.0 } 294 | ``` 295 | 296 | -------------------------------------------------------------------------------- /benches/bench.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use aqueue::{Actor, RwModel}; 3 | use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion}; 4 | use tokio::join; 5 | 6 | #[derive(Default, Debug)] 7 | struct TestBench { 8 | i: usize, 9 | } 10 | 11 | impl TestBench { 12 | #[inline] 13 | fn add(&mut self, i: usize) { 14 | self.i += i; 15 | } 16 | 17 | #[inline] 18 | fn clean(&mut self) { 19 | self.i = 0; 20 | } 21 | } 22 | 23 | trait ITestBench { 24 | async fn add(&self, i: usize) -> Result<()>; 25 | async fn clean(&self) -> Result<()>; 26 | fn get(&self) -> usize; 27 | } 28 | 29 | impl ITestBench for Actor { 30 | #[inline] 31 | async fn add(&self, i: usize) -> Result<()> { 32 | self.inner_call(|inner| async move { 33 | inner.get_mut().add(i); 34 | Ok(()) 35 | }) 36 | .await 37 | } 38 | 39 | #[inline] 40 | async fn clean(&self) -> Result<()> { 41 | self.inner_call(|inner| async move { 42 | inner.get_mut().clean(); 43 | Ok(()) 44 | }) 45 | .await 46 | } 47 | 48 | #[inline] 49 | fn get(&self) -> usize { 50 | unsafe { self.deref_inner().i } 51 | } 52 | } 53 | 54 | impl ITestBench for RwModel { 55 | #[inline] 56 | async fn add(&self, i: usize) -> Result<()> { 57 | self.call_mut(|mut inner| async move { 58 | inner.add(i); 59 | Ok(()) 60 | }) 61 | .await 62 | } 63 | 64 | #[inline] 65 | async fn clean(&self) -> Result<()> { 66 | self.call_mut(|mut inner| async move { 67 | inner.clean(); 68 | Ok(()) 69 | }) 70 | .await 71 | } 72 | 73 | #[inline] 74 | fn get(&self) -> usize { 75 | self.sync_mut_call(|inner| inner.i) 76 | } 77 | } 78 | 79 | lazy_static::lazy_static! { 80 | static ref BENCH_DATA:Actor={ 81 | Actor::new(TestBench::default()) 82 | }; 83 | 84 | static ref BENCH_MODEL:RwModel={ 85 | RwModel::new(TestBench::default()) 86 | }; 87 | } 88 | 89 | fn benchmark(c: &mut Criterion) { 90 | let size: usize = 100000; 91 | c.bench_with_input(BenchmarkId::new("single_task_actor_call", size), &size, |b, &s| { 92 | // Insert a call to `to_async` to convert the bencher to async mode. 93 | // The timing loops are the same as with the normal bencher. 94 | b.to_async(tokio::runtime::Builder::new_current_thread().build().unwrap()) 95 | .iter(|| single_task_test(s)); 96 | }); 97 | 98 | println!("single_task_test all:{}", BENCH_DATA.get()); 99 | 100 | c.bench_with_input(BenchmarkId::new("multi_task_actor_call", size), &size, |b, &s| { 101 | // Insert a call to `to_async` to convert the bencher to async mode. 102 | // The timing loops are the same as with the normal bencher. 103 | b.to_async(tokio::runtime::Builder::new_multi_thread().build().unwrap()) 104 | .iter(|| multi_task_test(s / 2)); 105 | }); 106 | 107 | println!("multi_task_test all:{}", BENCH_DATA.get()); 108 | 109 | c.bench_with_input(BenchmarkId::new("single_task_model_call", size), &size, |b, &s| { 110 | // Insert a call to `to_async` to convert the bencher to async mode. 111 | // The timing loops are the same as with the normal bencher. 112 | b.to_async(tokio::runtime::Builder::new_current_thread().build().unwrap()) 113 | .iter(|| single_task_test_model(s)); 114 | }); 115 | 116 | println!("rw single_task_test all:{}", BENCH_MODEL.get()); 117 | 118 | c.bench_with_input(BenchmarkId::new("multi_task_model_call", size), &size, |b, &s| { 119 | // Insert a call to `to_async` to convert the bencher to async mode. 120 | // The timing loops are the same as with the normal bencher. 121 | b.to_async(tokio::runtime::Builder::new_multi_thread().build().unwrap()) 122 | .iter(|| multi_task_test_model(s / 2)); 123 | }); 124 | 125 | println!("rw multi_task_test all:{}", BENCH_MODEL.get()); 126 | } 127 | 128 | async fn single_task_test(size: usize) { 129 | BENCH_DATA.clean().await.unwrap(); 130 | for i in 0..size { 131 | BENCH_DATA.add(i).await.unwrap(); 132 | } 133 | } 134 | 135 | async fn multi_task_test(size: usize) { 136 | BENCH_DATA.clean().await.unwrap(); 137 | let a = tokio::spawn(async move { 138 | for i in 0..size { 139 | BENCH_DATA.add(i).await.unwrap(); 140 | } 141 | }); 142 | 143 | let b = tokio::spawn(async move { 144 | for i in 0..size { 145 | BENCH_DATA.add(i).await.unwrap(); 146 | } 147 | }); 148 | 149 | let _ = join!(a, b); 150 | } 151 | 152 | async fn single_task_test_model(size: usize) { 153 | BENCH_MODEL.clean().await.unwrap(); 154 | for i in 0..size { 155 | BENCH_MODEL.add(i).await.unwrap(); 156 | } 157 | } 158 | 159 | async fn multi_task_test_model(size: usize) { 160 | BENCH_MODEL.clean().await.unwrap(); 161 | let a = tokio::spawn(async move { 162 | for i in 0..size { 163 | BENCH_MODEL.add(i).await.unwrap(); 164 | } 165 | }); 166 | 167 | let b = tokio::spawn(async move { 168 | for i in 0..size { 169 | BENCH_MODEL.add(i).await.unwrap(); 170 | } 171 | }); 172 | 173 | let _ = join!(a, b); 174 | } 175 | 176 | criterion_group!(benches, benchmark); 177 | criterion_main!(benches); 178 | -------------------------------------------------------------------------------- /examples/nums.rs: -------------------------------------------------------------------------------- 1 | use aqueue::Actor; 2 | 3 | use std::sync::Arc; 4 | use std::time::Instant; 5 | use tokio::try_join; 6 | 7 | #[derive(Default)] 8 | struct Foo { 9 | count: u64, 10 | i: i128, 11 | } 12 | 13 | impl Foo { 14 | pub fn add(&mut self, x: i32) -> i128 { 15 | self.count += 1; 16 | self.i += x as i128; 17 | self.i 18 | } 19 | fn reset(&mut self) { 20 | self.count = 0; 21 | self.i = 0; 22 | } 23 | pub fn get(&self) -> i128 { 24 | self.i 25 | } 26 | pub fn get_count(&self) -> u64 { 27 | self.count 28 | } 29 | } 30 | 31 | trait FooRunner { 32 | async fn add(&self, x: i32) -> i128; 33 | async fn reset(&self); 34 | async fn get(&self) -> i128; 35 | async fn get_count(&self) -> u64; 36 | } 37 | 38 | impl FooRunner for Actor { 39 | async fn add(&self, x: i32) -> i128 { 40 | self.inner_call(|inner| async move { inner.get_mut().add(x) }).await 41 | } 42 | async fn reset(&self) { 43 | self.inner_call(|inner| async move { inner.get_mut().reset() }).await 44 | } 45 | async fn get(&self) -> i128 { 46 | self.inner_call(|inner| async move { inner.get_mut().get() }).await 47 | } 48 | async fn get_count(&self) -> u64 { 49 | self.inner_call(|inner| async move { inner.get_mut().get_count() }).await 50 | } 51 | } 52 | 53 | #[tokio::main] 54 | async fn main() -> anyhow::Result<()> { 55 | { 56 | // Single thread test 57 | let tf = Actor::new(Foo::default()); 58 | tf.add(100).await; 59 | assert_eq!(100, tf.get().await); 60 | tf.add(-100).await; 61 | assert_eq!(0, tf.get().await); 62 | tf.reset().await; 63 | 64 | let start = Instant::now(); 65 | for i in 0..100000000 { 66 | tf.add(i).await; 67 | } 68 | 69 | println!( 70 | "test a count:{} value:{} time:{} qps:{}", 71 | tf.get_count().await, 72 | tf.get().await, 73 | start.elapsed().as_secs_f32(), 74 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 75 | ); 76 | } 77 | 78 | { 79 | //Multithreading test 80 | let tf = Arc::new(Actor::new(Foo::default())); 81 | let start = Instant::now(); 82 | let a_tf = tf.clone(); 83 | let a = tokio::spawn(async move { 84 | for i in 0..25000000 { 85 | a_tf.add(i).await; 86 | } 87 | }); 88 | 89 | let b_tf = tf.clone(); 90 | let b = tokio::spawn(async move { 91 | for i in 25000000..50000000 { 92 | b_tf.add(i).await; 93 | } 94 | }); 95 | 96 | let c_tf = tf.clone(); 97 | let c = tokio::spawn(async move { 98 | for i in 50000000..75000000 { 99 | c_tf.add(i).await; 100 | } 101 | }); 102 | 103 | let d_tf = tf.clone(); 104 | let d = tokio::spawn(async move { 105 | for i in 75000000..100000000 { 106 | d_tf.add(i).await; 107 | } 108 | }); 109 | 110 | try_join!(a, b, c, d)?; 111 | 112 | println!( 113 | "test b count:{} value:{} time:{} qps:{}", 114 | tf.get_count().await, 115 | tf.get().await, 116 | start.elapsed().as_secs_f32(), 117 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 118 | ); 119 | } 120 | 121 | Ok(()) 122 | } 123 | -------------------------------------------------------------------------------- /examples/nums_rw.rs: -------------------------------------------------------------------------------- 1 | use aqueue::RwModel; 2 | 3 | use std::sync::Arc; 4 | use std::time::Instant; 5 | use tokio::try_join; 6 | 7 | #[derive(Default)] 8 | struct Foo { 9 | count: u64, 10 | i: i128, 11 | } 12 | 13 | impl Foo { 14 | pub fn add(&mut self, x: i32) -> i128 { 15 | self.count += 1; 16 | self.i += x as i128; 17 | self.i 18 | } 19 | fn reset(&mut self) { 20 | self.count = 0; 21 | self.i = 0; 22 | } 23 | pub fn get(&self) -> i128 { 24 | self.i 25 | } 26 | pub fn get_count(&self) -> u64 { 27 | self.count 28 | } 29 | } 30 | 31 | trait FooRunner { 32 | async fn add(&self, x: i32) -> i128; 33 | async fn reset(&self); 34 | async fn get(&self) -> i128; 35 | async fn get_count(&self) -> u64; 36 | } 37 | 38 | impl FooRunner for RwModel { 39 | async fn add(&self, x: i32) -> i128 { 40 | self.call_mut(|mut inner| async move { inner.add(x) }).await 41 | } 42 | async fn reset(&self) { 43 | self.call_mut(|mut inner| async move { inner.reset() }).await 44 | } 45 | async fn get(&self) -> i128 { 46 | self.call(|inner| async move { inner.get() }).await 47 | } 48 | async fn get_count(&self) -> u64 { 49 | self.call(|inner| async move { inner.get_count() }).await 50 | } 51 | } 52 | 53 | #[tokio::main] 54 | async fn main() -> anyhow::Result<()> { 55 | { 56 | // Single thread test 57 | let tf = RwModel::new(Foo::default()); 58 | tf.add(100).await; 59 | assert_eq!(100, tf.get().await); 60 | tf.add(-100).await; 61 | assert_eq!(0, tf.get().await); 62 | tf.reset().await; 63 | 64 | let start = Instant::now(); 65 | for i in 0..100000000 { 66 | tf.add(i).await; 67 | } 68 | 69 | println!( 70 | "test rw a count:{} value:{} time:{} qps:{}", 71 | tf.get_count().await, 72 | tf.get().await, 73 | start.elapsed().as_secs_f32(), 74 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 75 | ); 76 | } 77 | 78 | { 79 | //Multithreading test 80 | let tf = Arc::new(RwModel::new(Foo::default())); 81 | let start = Instant::now(); 82 | let a_tf = tf.clone(); 83 | let a = tokio::spawn(async move { 84 | for i in 0..25000000 { 85 | a_tf.add(i).await; 86 | } 87 | }); 88 | 89 | let b_tf = tf.clone(); 90 | let b = tokio::spawn(async move { 91 | for i in 25000000..50000000 { 92 | b_tf.add(i).await; 93 | } 94 | }); 95 | 96 | let c_tf = tf.clone(); 97 | let c = tokio::spawn(async move { 98 | for i in 50000000..75000000 { 99 | c_tf.add(i).await; 100 | } 101 | }); 102 | 103 | let d_tf = tf.clone(); 104 | let d = tokio::spawn(async move { 105 | for i in 75000000..100000000 { 106 | d_tf.add(i).await; 107 | } 108 | }); 109 | 110 | try_join!(a, b, c, d)?; 111 | 112 | println!( 113 | "test rw b count:{} value:{} time:{} qps:{}", 114 | tf.get_count().await, 115 | tf.get().await, 116 | start.elapsed().as_secs_f32(), 117 | tf.get_count().await / start.elapsed().as_millis() as u64 * 1000 118 | ); 119 | } 120 | 121 | Ok(()) 122 | } 123 | -------------------------------------------------------------------------------- /examples/table.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE "user" ( 2 | "id" integer NOT NULL PRIMARY KEY, 3 | "name" text, 4 | "gold" real 5 | ); -------------------------------------------------------------------------------- /examples/test_sqlx.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use aqueue::{inner_wait, Actor}; 3 | use sqlx::sqlite::SqlitePoolOptions; 4 | use sqlx::SqlitePool; 5 | use std::env; 6 | use tokio::task::JoinHandle; 7 | 8 | #[derive(sqlx::FromRow, Debug)] 9 | #[allow(dead_code)] 10 | pub struct User { 11 | id: i64, 12 | name: String, 13 | gold: f64, 14 | } 15 | 16 | pub struct DataBases { 17 | auto_id: u32, 18 | pool: SqlitePool, 19 | } 20 | 21 | unsafe impl Send for DataBases {} 22 | unsafe impl Sync for DataBases {} 23 | 24 | impl DataBases { 25 | pub fn new(sqlite_max_connections: u32) -> Result> { 26 | let pool = SqlitePoolOptions::new() 27 | .max_connections(sqlite_max_connections) 28 | .connect_lazy(&env::var("DATABASE_URL")?)?; 29 | 30 | Ok(Actor::new(DataBases { auto_id: 0, pool })) 31 | } 32 | /// create user table from table.sql 33 | async fn create_table(&self) -> Result<()> { 34 | sqlx::query(include_str!("table.sql")).execute(&self.pool).await?; 35 | Ok(()) 36 | } 37 | /// insert user data 38 | async fn insert_user(&mut self, name: &str, gold: f64) -> Result { 39 | self.auto_id += 1; 40 | let row = sqlx::query( 41 | r#" 42 | insert into `user`(`id`,`name`,`gold`) 43 | values(?,?,?) 44 | "#, 45 | ) 46 | .bind(&self.auto_id) 47 | .bind(name) 48 | .bind(gold) 49 | .execute(&self.pool) 50 | .await? 51 | .rows_affected(); 52 | 53 | Ok(row == 1) 54 | } 55 | /// insert user data 56 | async fn select_all_users(&self) -> Result> { 57 | Ok(sqlx::query_as::<_, User>("select * from `user`").fetch_all(&self.pool).await?) 58 | } 59 | } 60 | 61 | pub(crate) trait IDatabase { 62 | /// create user table from table.sql 63 | async fn create_table(&self) -> Result<()>; 64 | /// insert user data 65 | async fn insert_user(&self, name: String, gold: f64) -> Result; 66 | /// insert user data 67 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result; 68 | /// select all users table 69 | async fn select_all_users(&self) -> Result>; 70 | /// ERROR example 71 | /// call test_unsafe_block thread blocking 72 | /// i use timeout to block unlimited thread blocking 73 | /// 74 | /// 75 | /// call DB test_unsafe_blocking 76 | /// ────────────────────┐ 77 | /// │ 78 | /// │ 79 | /// ┌───────────────▼────────────┐ 80 | /// │ inner call lock current │ 81 | /// ┌──►│ thread │ 82 | /// │ └───────────────┬────────────┘ 83 | /// │ │ 84 | /// │ ▼ 85 | /// │ call insert_user will lock the current thread again 86 | /// │ current thread unlimited blocking 87 | /// │ │ 88 | /// └───────────────────┘ 89 | /// 90 | async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result; 91 | } 92 | 93 | impl IDatabase for Actor { 94 | async fn create_table(&self) -> Result<()> { 95 | self.inner_call(|inner| async move { inner.get().create_table().await }).await 96 | } 97 | async fn insert_user(&self, name: String, gold: f64) -> Result { 98 | self.inner_call(|inner| async move { inner.get_mut().insert_user(&name, gold).await }) 99 | .await 100 | } 101 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result { 102 | self.inner_call(|inner| async move { inner.get_mut().insert_user(name, gold).await }) 103 | .await 104 | } 105 | 106 | async fn select_all_users(&self) -> Result> { 107 | unsafe { 108 | // warn: 109 | // This is a thread unsafe way to get 110 | // When using, please make sure there is no thread safety problem 111 | self.deref_inner().select_all_users().await 112 | } 113 | } 114 | 115 | async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 116 | inner_wait!(self, 3000, |_| async move { DB.insert_user(name, gold).await }).await? 117 | } 118 | } 119 | 120 | lazy_static::lazy_static! { 121 | /// default global static database actor obj 122 | static ref DB:Actor={ 123 | DataBases::new(50).expect("install db error") 124 | }; 125 | } 126 | 127 | #[tokio::main] 128 | async fn main() -> Result<()> { 129 | dotenv::dotenv().ok().ok_or_else(|| anyhow!(".env file not found"))?; 130 | DB.create_table().await?; 131 | let mut join_vec = Vec::with_capacity(100); 132 | // create 100 tokio task run it. 133 | for i in 0..100 { 134 | let join: JoinHandle> = tokio::spawn(async move { 135 | //each task runs 1000 times 136 | for j in 0..1000 { 137 | DB.insert_user(i.to_string(), j as f64).await?; 138 | } 139 | Ok(()) 140 | }); 141 | 142 | join_vec.push(join); 143 | } 144 | //wait all task finish 145 | for join in join_vec { 146 | join.await??; 147 | } 148 | // print all users 149 | for user in DB.select_all_users().await? { 150 | println!("{:?}", user); 151 | } 152 | 153 | DB.test_unsafe_blocking("123123".to_string(), 1111111f64).await?; 154 | 155 | Ok(()) 156 | } 157 | -------------------------------------------------------------------------------- /examples/test_sqlx_rw_model.rs: -------------------------------------------------------------------------------- 1 | use anyhow::{anyhow, Result}; 2 | use aqueue::{call_wait, RwModel}; 3 | use sqlx::sqlite::SqlitePoolOptions; 4 | use sqlx::SqlitePool; 5 | use std::env; 6 | use tokio::task::JoinHandle; 7 | 8 | #[derive(sqlx::FromRow, Debug)] 9 | #[allow(dead_code)] 10 | pub struct User { 11 | id: i64, 12 | name: String, 13 | gold: f64, 14 | } 15 | 16 | pub struct DataBases { 17 | auto_id: u32, 18 | pool: SqlitePool, 19 | } 20 | 21 | unsafe impl Send for DataBases {} 22 | unsafe impl Sync for DataBases {} 23 | 24 | impl DataBases { 25 | pub fn new(sqlite_max_connections: u32) -> Result> { 26 | let pool = SqlitePoolOptions::new() 27 | .max_connections(sqlite_max_connections) 28 | .connect_lazy(&env::var("DATABASE_URL")?)?; 29 | 30 | Ok(RwModel::new(DataBases { auto_id: 0, pool })) 31 | } 32 | /// create user table from table.sql 33 | async fn create_table(&self) -> Result<()> { 34 | sqlx::query(include_str!("table.sql")).execute(&self.pool).await?; 35 | Ok(()) 36 | } 37 | /// insert user data 38 | async fn insert_user(&mut self, name: &str, gold: f64) -> Result { 39 | self.auto_id += 1; 40 | let row = sqlx::query( 41 | r#" 42 | insert into `user`(`id`,`name`,`gold`) 43 | values(?,?,?) 44 | "#, 45 | ) 46 | .bind(&self.auto_id) 47 | .bind(name) 48 | .bind(gold) 49 | .execute(&self.pool) 50 | .await? 51 | .rows_affected(); 52 | 53 | Ok(row == 1) 54 | } 55 | /// insert user data 56 | async fn select_all_users(&self) -> Result> { 57 | Ok(sqlx::query_as::<_, User>("select * from `user`").fetch_all(&self.pool).await?) 58 | } 59 | } 60 | 61 | pub(crate) trait IDatabase { 62 | /// create user table from table.sql 63 | async fn create_table(&self) -> Result<()>; 64 | /// insert user data 65 | async fn insert_user(&self, name: String, gold: f64) -> Result; 66 | /// insert user data 67 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result; 68 | /// select all users table 69 | async fn select_all_users(&self) -> Result>; 70 | /// ERROR example 71 | /// call test_unsafe_block thread blocking 72 | /// i use timeout to block unlimited thread blocking 73 | /// 74 | /// 75 | /// call DB test_unsafe_blocking 76 | /// ────────────────────┐ 77 | /// │ 78 | /// │ 79 | /// ┌───────────────▼────────────┐ 80 | /// │ inner call lock current │ 81 | /// ┌──►│ thread │ 82 | /// │ └───────────────┬────────────┘ 83 | /// │ │ 84 | /// │ ▼ 85 | /// │ call insert_user will lock the current thread again 86 | /// │ current thread unlimited blocking 87 | /// │ │ 88 | /// └───────────────────┘ 89 | /// 90 | async fn test_unsafe_blocking(&self, name: &str, gold: f64) -> Result; 91 | } 92 | 93 | impl IDatabase for RwModel { 94 | async fn create_table(&self) -> Result<()> { 95 | self.call_mut(|inner| async move { inner.create_table().await }).await 96 | } 97 | async fn insert_user(&self, name: String, gold: f64) -> Result { 98 | self.call_mut(|mut inner| async move { inner.insert_user(&name, gold).await }).await 99 | } 100 | async fn insert_user_ref_name(&self, name: &str, gold: f64) -> Result { 101 | self.call_mut(|mut inner| async move { inner.insert_user(name, gold).await }).await 102 | } 103 | 104 | async fn select_all_users(&self) -> Result> { 105 | self.call(|inner| async move { inner.select_all_users().await }).await 106 | } 107 | 108 | async fn test_unsafe_blocking(&self, name: &str, gold: f64) -> Result { 109 | call_wait!(self, 3000, |_inner| async move { DB.insert_user_ref_name(name, gold).await }).await? 110 | } 111 | } 112 | 113 | lazy_static::lazy_static! { 114 | /// default global static database actor obj 115 | static ref DB:RwModel={ 116 | DataBases::new(50).expect("install db error") 117 | }; 118 | } 119 | 120 | #[tokio::main] 121 | async fn main() -> Result<()> { 122 | dotenv::dotenv().ok().ok_or_else(|| anyhow!(".env file not found"))?; 123 | DB.create_table().await?; 124 | let mut join_vec = Vec::with_capacity(100); 125 | // create 100 tokio task run it. 126 | for i in 0..100 { 127 | let join: JoinHandle> = tokio::spawn(async move { 128 | //each task runs 1000 times 129 | for j in 0..1000 { 130 | DB.insert_user(i.to_string(), j as f64).await?; 131 | } 132 | Ok(()) 133 | }); 134 | 135 | join_vec.push(join); 136 | } 137 | //wait all task finish 138 | for join in join_vec { 139 | join.await??; 140 | } 141 | // print all users 142 | for user in DB.select_all_users().await? { 143 | println!("{:?}", user); 144 | } 145 | 146 | DB.test_unsafe_blocking("123123", 1111111f64).await?; 147 | 148 | Ok(()) 149 | } 150 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | brace_style="PreferSameLine" 2 | fn_args_layout="Compressed" 3 | imports_indent="Visual" 4 | max_width=150 -------------------------------------------------------------------------------- /src/actor.rs: -------------------------------------------------------------------------------- 1 | use crate::AQueue; 2 | 3 | use crate::inner_store::InnerStore; 4 | use std::future::Future; 5 | use std::ops::Deref; 6 | use std::sync::Arc; 7 | 8 | /// Actor Model 9 | /// Ensure Thread safety and high performance writing 10 | pub struct Actor { 11 | inner: Arc>, 12 | queue: AQueue, 13 | } 14 | 15 | impl Default for Actor { 16 | fn default() -> Self { 17 | Self { 18 | inner: Arc::new(InnerStore::new(Default::default())), 19 | queue: AQueue::new(), 20 | } 21 | } 22 | } 23 | 24 | pub struct RefInner<'a, T: ?Sized> { 25 | pub(crate) value: &'a T, 26 | } 27 | 28 | impl Deref for RefInner<'_, T> { 29 | type Target = T; 30 | 31 | fn deref(&self) -> &Self::Target { 32 | self.value 33 | } 34 | } 35 | 36 | impl Actor { 37 | #[inline] 38 | pub fn new(x: I) -> Actor { 39 | Actor { 40 | inner: Arc::new(InnerStore::new(x)), 41 | queue: AQueue::new(), 42 | } 43 | } 44 | 45 | /// Behavior through queues,thread safe call async fn 46 | #[inline] 47 | pub async fn inner_call(&self, call: impl FnOnce(Arc>) -> T) -> R 48 | where 49 | T: Future, 50 | { 51 | self.queue.run(call, self.inner.clone()).await 52 | } 53 | 54 | /// # Safety 55 | /// This is a thread unsafe way to get 56 | /// When using, please make sure there is no thread safety problem 57 | #[inline] 58 | pub unsafe fn deref_inner(&self) -> RefInner<'_, I> { 59 | RefInner { value: self.inner.get() } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/inner_store.rs: -------------------------------------------------------------------------------- 1 | use std::cell::UnsafeCell; 2 | 3 | /// Inner impl 4 | /// # Safety 5 | /// This is Thread Unsafe,Please do not use it at will. 6 | pub struct InnerStore(UnsafeCell); 7 | unsafe impl Sync for InnerStore {} 8 | unsafe impl Send for InnerStore {} 9 | 10 | impl InnerStore { 11 | #[inline] 12 | pub(crate) fn new(x: T) -> InnerStore { 13 | InnerStore(UnsafeCell::new(x)) 14 | } 15 | #[inline] 16 | #[allow(clippy::mut_from_ref)] 17 | pub fn get_mut(&self) -> &mut T { 18 | unsafe { &mut *self.0.get() } 19 | } 20 | #[inline] 21 | pub fn get(&self) -> &T { 22 | unsafe { &*self.0.get() } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | mod actor; 2 | mod inner_store; 3 | mod mutex; 4 | mod pc_model; 5 | mod rw_model; 6 | mod rwlock; 7 | mod semaphore; 8 | 9 | pub use actor::Actor; 10 | pub use mutex::AQueue; 11 | pub use pc_model::PCModel; 12 | pub use rw_model::RwModel; 13 | pub use rwlock::RwQueue; 14 | pub use semaphore::SemaphoreQueue; 15 | 16 | /// inner call wait ms throw time error 17 | /// need on feature "tokio_time" or "async_std_time" 18 | /// # tokio runtime: 19 | /// ``` toml 20 | /// aqueue = { version = "^1.2.10", features = ["tokio_time"] } 21 | /// ``` 22 | /// # Example 23 | /// ``` ignore 24 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 25 | /// inner_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 26 | /// } 27 | /// ``` 28 | #[cfg(all(feature = "tokio_time", not(feature = "async_std_time")))] 29 | #[macro_export] 30 | macro_rules! inner_wait { 31 | ($actor:expr,$timeout:expr,$fun:expr) => { 32 | tokio::time::timeout(std::time::Duration::from_millis($timeout), $actor.inner_call($fun)) 33 | }; 34 | } 35 | 36 | /// inner call wait ms throw time error 37 | /// need on feature "tokio_time" or "async_std_time" 38 | /// # async_std runtime: 39 | /// ``` toml 40 | /// aqueue = { version = "^1.2.10", features = ["async_std_time"] } 41 | /// ``` 42 | /// # Example 43 | /// ``` ignore 44 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 45 | /// inner_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 46 | /// } 47 | /// ``` 48 | #[cfg(all(feature = "async_std_time", not(feature = "tokio_time")))] 49 | #[macro_export] 50 | macro_rules! inner_wait { 51 | ($actor:expr,$timeout:expr,$fun:expr) => { 52 | async_std::future::timeout(std::time::Duration::from_millis($timeout), $actor.inner_call($fun)) 53 | }; 54 | } 55 | 56 | /// call_mut wait ms throw time error 57 | /// need on feature "tokio_time" or "async_std_time" 58 | /// # tokio runtime: 59 | /// ``` toml 60 | /// aqueue = { version = "^1.3.2", features = ["tokio_time"] } 61 | /// ``` 62 | /// # Example 63 | /// ``` ignore 64 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 65 | /// call_mut_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 66 | /// } 67 | /// ``` 68 | #[cfg(all(feature = "tokio_time", not(feature = "async_std_time")))] 69 | #[macro_export] 70 | macro_rules! call_mut_wait { 71 | ($model:expr,$timeout:expr,$fun:expr) => { 72 | tokio::time::timeout(std::time::Duration::from_millis($timeout), $model.call_mut($fun)) 73 | }; 74 | } 75 | 76 | /// call_mut wait ms throw time error 77 | /// need on feature "tokio_time" or "async_std_time" 78 | /// # tokio runtime: 79 | /// ``` toml 80 | /// aqueue = { version = "^1.3.2", features = ["async_std_time"] } 81 | /// ``` 82 | /// # Example 83 | /// ``` ignore 84 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 85 | /// call_mut_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 86 | /// } 87 | /// ``` 88 | #[cfg(all(feature = "async_std_time", not(feature = "tokio_time")))] 89 | #[macro_export] 90 | macro_rules! call_mut_wait { 91 | ($model:expr,$timeout:expr,$fun:expr) => { 92 | async_std::future::timeout(std::time::Duration::from_millis($timeout), $model.call_mut($fun)) 93 | }; 94 | } 95 | 96 | /// call wait ms throw time error 97 | /// need on feature "tokio_time" or "async_std_time" 98 | /// # tokio runtime: 99 | /// ``` toml 100 | /// aqueue = { version = "^1.3.2", features = ["tokio_time"] } 101 | /// ``` 102 | /// # Example 103 | /// ``` ignore 104 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 105 | /// call_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 106 | /// } 107 | /// ``` 108 | #[cfg(all(feature = "tokio_time", not(feature = "async_std_time")))] 109 | #[macro_export] 110 | macro_rules! call_wait { 111 | ($model:expr,$timeout:expr,$fun:expr) => { 112 | tokio::time::timeout(std::time::Duration::from_millis($timeout), $model.call($fun)) 113 | }; 114 | } 115 | 116 | /// call wait ms throw time error 117 | /// need on feature "tokio_time" or "async_std_time" 118 | /// # tokio runtime: 119 | /// ``` toml 120 | /// aqueue = { version = "^1.3.2", features = ["async_std_time"] } 121 | /// ``` 122 | /// # Example 123 | /// ``` ignore 124 | /// async fn test_unsafe_blocking(&self, name: String, gold: f64) -> Result { 125 | /// call_wait!(self, 30000, |_inner| async move { DB.insert_user(name, gold).await }).await? 126 | /// } 127 | /// ``` 128 | #[cfg(all(feature = "async_std_time", not(feature = "tokio_time")))] 129 | #[macro_export] 130 | macro_rules! call_wait { 131 | ($model:expr,$timeout:expr,$fun:expr) => { 132 | async_std::future::timeout(std::time::Duration::from_millis($timeout), $model.call($fun)) 133 | }; 134 | } 135 | -------------------------------------------------------------------------------- /src/mutex/item.rs: -------------------------------------------------------------------------------- 1 | // use crate::mutex::IQueueItem; 2 | // use anyhow::{anyhow, Result}; 3 | // use async_oneshot::{oneshot, Receiver, Sender}; 4 | // use futures_util::ready; 5 | // use std::future::Future; 6 | // use std::pin::Pin; 7 | // use std::task::Poll; 8 | // 9 | // pin_project_lite::pin_project! { 10 | // /// AQueue run item 11 | // pub struct QueueItem { 12 | // #[pin] 13 | // call: Fu, 14 | // result_sender: Sender, 15 | // } 16 | // } 17 | // 18 | // impl IQueueItem for QueueItem {} 19 | // 20 | // impl QueueItem 21 | // where 22 | // Fu: Future, 23 | // { 24 | // #[inline] 25 | // pub fn new(call: Fu) -> (Receiver, Self) { 26 | // let (result_sender, result_receiver) = oneshot(); 27 | // (result_receiver, Self { call, result_sender }) 28 | // } 29 | // } 30 | // 31 | // impl Future for QueueItem { 32 | // type Output = Result<()>; 33 | // 34 | // #[inline] 35 | // fn poll(self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll { 36 | // let my = self.project(); 37 | // Poll::Ready(my.result_sender.send(ready!(my.call.poll(cx))).map_err(|_| anyhow!("rx is close"))) 38 | // } 39 | // } 40 | -------------------------------------------------------------------------------- /src/mutex/mod.rs: -------------------------------------------------------------------------------- 1 | use async_lock::Mutex; 2 | use std::future::Future; 3 | use std::hint::spin_loop; 4 | 5 | /// async future thread safe mutex 6 | pub struct AQueue { 7 | lock: Mutex<()>, 8 | } 9 | 10 | impl Default for AQueue { 11 | #[inline] 12 | fn default() -> Self { 13 | AQueue { lock: Mutex::new(()) } 14 | } 15 | } 16 | 17 | impl AQueue { 18 | #[inline] 19 | pub fn new() -> AQueue { 20 | AQueue::default() 21 | } 22 | 23 | /// Sync run fn 24 | /// Note: it is not based on fair lock. It will never be called when the mutex has unprocessed 25 | #[inline] 26 | pub fn sync_run(&self, call: impl FnOnce(A) -> R, arg: A) -> R { 27 | loop { 28 | let guard = self.lock.try_lock(); 29 | if guard.is_some() { 30 | return call(arg); 31 | } else { 32 | spin_loop(); 33 | } 34 | } 35 | } 36 | 37 | /// Async lock run fn 38 | /// The greatest truths are the simplest 39 | #[inline] 40 | pub async fn run(&self, call: impl FnOnce(A) -> T, arg: A) -> R 41 | where 42 | T: Future, 43 | { 44 | let _guard = self.lock.lock().await; 45 | call(arg).await 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/pc_model.rs: -------------------------------------------------------------------------------- 1 | use super::semaphore::SemaphoreQueue; 2 | use std::future::Future; 3 | 4 | /// parallelism control model 5 | /// The PCModel is a model that can be used to control task parallelism number 6 | pub struct PCModel { 7 | inner: I, 8 | queue: SemaphoreQueue, 9 | } 10 | 11 | impl PCModel { 12 | /// Create a new PCModel 13 | #[inline] 14 | pub fn new(inner: I, n: usize) -> Self { 15 | PCModel { 16 | inner, 17 | queue: SemaphoreQueue::new(n), 18 | } 19 | } 20 | 21 | /// Get the inner value reference 22 | #[inline] 23 | pub fn inner(&self) -> &I { 24 | &self.inner 25 | } 26 | 27 | /// Behavior through queues,thread parallelism control call async fn read ref 28 | #[inline] 29 | pub async fn call<'a, T, R>(&'a self, call: impl FnOnce(&'a I) -> T) -> R 30 | where 31 | T: Future, 32 | { 33 | self.queue.run(call, &self.inner).await 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/rw_model.rs: -------------------------------------------------------------------------------- 1 | use crate::actor::RefInner; 2 | use crate::inner_store::InnerStore; 3 | use crate::RwQueue; 4 | use std::future::Future; 5 | use std::ops::{Deref, DerefMut}; 6 | 7 | /// RwMode mut ref 8 | pub struct RefMutInner<'a, T: ?Sized> { 9 | pub(crate) value: &'a mut T, 10 | } 11 | 12 | impl<'a, T> RefMutInner<'a, T> { 13 | #[inline] 14 | pub fn new(value: &'a mut T) -> Self { 15 | Self { value } 16 | } 17 | } 18 | 19 | impl Deref for RefMutInner<'_, T> { 20 | type Target = T; 21 | fn deref(&self) -> &Self::Target { 22 | self.value 23 | } 24 | } 25 | 26 | impl DerefMut for RefMutInner<'_, T> { 27 | fn deref_mut(&mut self) -> &mut Self::Target { 28 | self.value 29 | } 30 | } 31 | 32 | /// RwModel 33 | /// Ensure Thread safety and high performance reading and writing 34 | pub struct RwModel { 35 | inner: InnerStore, 36 | queue: RwQueue, 37 | } 38 | 39 | impl Default for RwModel { 40 | fn default() -> Self { 41 | Self { 42 | inner: InnerStore::new(Default::default()), 43 | queue: RwQueue::new(), 44 | } 45 | } 46 | } 47 | 48 | impl RwModel { 49 | #[inline] 50 | pub fn new(x: I) -> RwModel { 51 | RwModel { 52 | inner: InnerStore::new(x), 53 | queue: RwQueue::new(), 54 | } 55 | } 56 | 57 | /// Behavior through queues,thread safe call async fn write ref mut 58 | #[inline] 59 | pub async fn call_mut<'a, T, R>(&'a self, call: impl FnOnce(RefMutInner<'a, I>) -> T) -> R 60 | where 61 | T: Future, 62 | { 63 | self.queue.write_run(call, self.inner.get_mut()).await 64 | } 65 | 66 | /// Behavior through queues,thread safe call async fn read ref 67 | #[inline] 68 | pub async fn call<'a, T, R>(&'a self, call: impl FnOnce(RefInner<'a, I>) -> T) -> R 69 | where 70 | T: Future, 71 | { 72 | self.queue.read_run(call, self.inner.get()).await 73 | } 74 | 75 | ///Thread safe call async fn read, Balanced queues are not supported 76 | #[inline] 77 | pub fn sync_call(&self, call: impl FnOnce(&I) -> R) -> R { 78 | self.queue.sync_read_run(call, self.inner.get()) 79 | } 80 | 81 | ///Thread safe call async fn write, Balanced queues are not supported 82 | #[inline] 83 | pub fn sync_mut_call(&self, call: impl FnOnce(RefMutInner<'_, I>) -> R) -> R { 84 | self.queue.sync_write_run(call, RefMutInner { value: self.inner.get_mut() }) 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/rwlock/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::actor::RefInner; 2 | use crate::rw_model::RefMutInner; 3 | use async_lock::RwLock; 4 | use std::future::Future; 5 | use std::hint::spin_loop; 6 | 7 | /// async future thread safe mutex for Rwlock 8 | pub struct RwQueue { 9 | lock: RwLock<()>, 10 | } 11 | 12 | impl Default for RwQueue { 13 | #[inline] 14 | fn default() -> Self { 15 | RwQueue { lock: RwLock::new(()) } 16 | } 17 | } 18 | 19 | impl RwQueue { 20 | #[inline] 21 | pub fn new() -> RwQueue { 22 | RwQueue::default() 23 | } 24 | 25 | /// Sync write run fn 26 | /// Note: it is not based on fair lock. It will never be called when the mutex has unprocessed 27 | #[inline] 28 | pub fn sync_write_run(&self, call: impl FnOnce(RefMutInner<'_, A>) -> R, arg: RefMutInner<'_, A>) -> R { 29 | loop { 30 | let guard = self.lock.try_write(); 31 | if guard.is_some() { 32 | return call(arg); 33 | } else { 34 | spin_loop(); 35 | } 36 | } 37 | } 38 | 39 | /// Sync run fn 40 | /// Note: it is not based on fair lock. It will never be called when the mutex has unprocessed 41 | #[inline] 42 | pub fn sync_read_run(&self, call: impl FnOnce(A) -> R, arg: A) -> R { 43 | loop { 44 | let guard = self.lock.try_read(); 45 | if guard.is_some() { 46 | return call(arg); 47 | } else { 48 | spin_loop(); 49 | } 50 | } 51 | } 52 | 53 | /// Async write run fn 54 | /// It is based on the principle of first in, first run 55 | #[inline] 56 | pub async fn write_run<'a, A, T, R>(&self, call: impl FnOnce(RefMutInner<'a, A>) -> T, arg: &'a mut A) -> R 57 | where 58 | T: Future, 59 | { 60 | let arg = RefMutInner { value: arg }; 61 | let _guard = self.lock.write().await; 62 | call(arg).await 63 | } 64 | 65 | /// Async write run fn 66 | /// It is based on the principle of first in, first run 67 | #[inline] 68 | pub async fn read_run<'a, A, T, R>(&self, call: impl FnOnce(RefInner<'a, A>) -> T, arg: &'a A) -> R 69 | where 70 | T: Future, 71 | { 72 | let arg = RefInner { value: arg }; 73 | let _guard = self.lock.read().await; 74 | call(arg).await 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/semaphore/mod.rs: -------------------------------------------------------------------------------- 1 | use async_lock::Semaphore; 2 | use std::future::Future; 3 | 4 | /// Used to control task parallelism queue 5 | pub struct SemaphoreQueue { 6 | semaphore: Semaphore, 7 | } 8 | 9 | impl Default for SemaphoreQueue { 10 | #[inline] 11 | fn default() -> Self { 12 | SemaphoreQueue { 13 | semaphore: Semaphore::new(5), 14 | } 15 | } 16 | } 17 | 18 | impl SemaphoreQueue { 19 | #[inline] 20 | pub fn new(n: usize) -> SemaphoreQueue { 21 | SemaphoreQueue { 22 | semaphore: Semaphore::new(n), 23 | } 24 | } 25 | 26 | #[inline] 27 | pub async fn run(&self, call: impl FnOnce(A) -> T, arg: A) -> R 28 | where 29 | T: Future, 30 | { 31 | let _guard = self.semaphore.acquire().await; 32 | call(arg).await 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/test.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use aqueue::{AQueue, Actor}; 3 | use futures_util::try_join; 4 | use std::cell::Cell; 5 | use std::sync::Arc; 6 | use std::time::Instant; 7 | use tokio::time::{sleep, Duration}; 8 | 9 | static mut VALUE: u64 = 0; 10 | 11 | #[tokio::test] 12 | async fn test_base() -> Result<()> { 13 | let queue = Arc::new(AQueue::new()); 14 | 15 | let a_queue = queue.clone(); 16 | tokio::spawn(async move { 17 | let x = a_queue 18 | .run( 19 | |_| async move { 20 | println!("a"); 21 | //delay_for(Duration::from_secs(1)).await; 22 | 1 23 | }, 24 | (), 25 | ) 26 | .await; 27 | 28 | println!("{:?}", x); 29 | }) 30 | .await?; 31 | 32 | let a_queue = queue.clone(); 33 | tokio::spawn(async move { 34 | for i in 0..100 { 35 | a_queue 36 | .run( 37 | |_| async move { 38 | println!("b:{}", i); 39 | () 40 | }, 41 | (), 42 | ) 43 | .await; 44 | } 45 | }) 46 | .await?; 47 | 48 | sleep(Duration::from_secs(2)).await; 49 | 50 | let start = Instant::now(); 51 | let mut v = 0u64; 52 | for i in 0..10000000 { 53 | v = queue 54 | .run( 55 | |x| async move { 56 | unsafe { 57 | VALUE += x; 58 | VALUE 59 | } 60 | }, 61 | i, 62 | ) 63 | .await; 64 | } 65 | 66 | println!("{} {}", start.elapsed().as_secs_f32(), v); 67 | 68 | assert_eq!(v, 49999995000000); 69 | 70 | Ok(()) 71 | } 72 | 73 | #[tokio::test] 74 | async fn test_string() -> Result<()> { 75 | let queue = Arc::new(AQueue::new()); 76 | let str = 12345.to_string(); 77 | let len = queue.run(|x| async move { x.len() }, str).await; 78 | assert_eq!(len, 5); 79 | struct Foo { 80 | i: i32, 81 | } 82 | let foo = Foo { i: 5 }; 83 | let len = queue.run(|x| async move { x.i }, foo).await; 84 | assert_eq!(len, 5); 85 | 86 | Ok(()) 87 | } 88 | 89 | #[tokio::test] 90 | async fn test_struct() -> Result<()> { 91 | #[async_trait::async_trait] 92 | trait IFoo { 93 | async fn run(&self, x: i32, y: i32) -> i32; 94 | fn get_count(&self) -> i32; 95 | } 96 | pub struct Foo { 97 | count: Cell, 98 | } 99 | 100 | unsafe impl Sync for Foo {} 101 | #[async_trait::async_trait] 102 | impl IFoo for Foo { 103 | async fn run(&self, x: i32, y: i32) -> i32 { 104 | self.count.set(self.count.get() + 1); 105 | x + y 106 | } 107 | 108 | fn get_count(&self) -> i32 { 109 | self.count.get() 110 | } 111 | } 112 | 113 | pub struct MakeActorIFoo { 114 | inner: Arc, 115 | queue: AQueue, 116 | } 117 | 118 | impl MakeActorIFoo { 119 | pub fn from(x: Foo) -> MakeActorIFoo { 120 | MakeActorIFoo { 121 | inner: Arc::new(x), 122 | queue: AQueue::new(), 123 | } 124 | } 125 | } 126 | 127 | #[async_trait::async_trait] 128 | impl IFoo for MakeActorIFoo { 129 | async fn run(&self, x: i32, y: i32) -> i32 { 130 | self.queue.run(|inner| async move { inner.run(x, y).await }, self.inner.clone()).await 131 | } 132 | 133 | fn get_count(&self) -> i32 { 134 | self.inner.get_count() 135 | } 136 | } 137 | 138 | let foo = Foo { count: Cell::new(0) }; 139 | let make = Arc::new(MakeActorIFoo::from(foo)); 140 | let x = make.run(1, 2).await; 141 | assert_eq!(x, 3); 142 | 143 | let begin = Instant::now(); 144 | let a_make = make.clone(); 145 | let a = tokio::spawn(async move { 146 | let start = Instant::now(); 147 | for i in 0..2000000 { 148 | a_make.run(i, i).await; 149 | } 150 | 151 | println!("a {} {}", start.elapsed().as_secs_f32(), a_make.inner.get_count()); 152 | }); 153 | 154 | let b_make = make.clone(); 155 | let b = tokio::spawn(async move { 156 | let start = Instant::now(); 157 | for i in 0..2000000 { 158 | b_make.run(i, i).await; 159 | } 160 | 161 | println!("b {} {}", start.elapsed().as_secs_f32(), b_make.inner.get_count()); 162 | }); 163 | 164 | let c = tokio::spawn(async move { 165 | let start = Instant::now(); 166 | for i in 0..2000000 { 167 | make.run(i, i).await; 168 | } 169 | println!("c {} {}", start.elapsed().as_secs_f32(), make.inner.get_count()); 170 | }); 171 | 172 | try_join!(a, b, c)?; 173 | 174 | println!("all secs:{}", begin.elapsed().as_secs_f32()); 175 | 176 | Ok(()) 177 | } 178 | 179 | #[tokio::test] 180 | async fn test_count() -> Result<()> { 181 | struct Foo { 182 | count: u64, 183 | data: String, 184 | } 185 | 186 | impl Foo { 187 | pub fn add_one(&mut self) { 188 | self.count += 1; 189 | self.data.push_str(&self.count.to_string()) 190 | } 191 | 192 | pub fn get_str(&self) -> String { 193 | self.data.clone() 194 | } 195 | } 196 | 197 | trait IFoo { 198 | async fn add_one(&self) -> Result<()>; 199 | async fn get_str(&self) -> Result; 200 | } 201 | 202 | impl IFoo for Actor { 203 | async fn add_one(&self) -> Result<()> { 204 | self.inner_call(|inner| async move { 205 | inner.get_mut().add_one(); 206 | Ok(()) 207 | }) 208 | .await 209 | } 210 | 211 | async fn get_str(&self) -> Result { 212 | self.inner_call(|inner| async move { Ok(inner.get_mut().get_str()) }).await 213 | } 214 | } 215 | 216 | let obj = Arc::new(Actor::new(Foo { 217 | count: 0, 218 | data: "".to_string(), 219 | })); 220 | 221 | let mut vec = vec![]; 222 | for _ in 0..1000 { 223 | let p_obj = obj.clone(); 224 | vec.push(tokio::spawn(async move { 225 | for _ in 0..1000 { 226 | p_obj.add_one().await.unwrap(); 227 | } 228 | })); 229 | } 230 | 231 | for j in vec { 232 | j.await?; 233 | } 234 | 235 | let mut check = Foo { 236 | count: 0, 237 | data: "".to_string(), 238 | }; 239 | 240 | for _ in 0..1000000 { 241 | check.add_one(); 242 | } 243 | 244 | let str = obj.get_str().await?; 245 | assert_eq!(str, check.get_str()); 246 | 247 | Ok(()) 248 | } 249 | 250 | #[tokio::test] 251 | async fn test_actor() -> Result<()> { 252 | #[derive(Default)] 253 | struct Foo { 254 | i: i32, 255 | x: i32, 256 | y: i32, 257 | } 258 | 259 | impl Foo { 260 | pub fn get(&self) -> (i32, i32, i32) { 261 | (self.i, self.x, self.y) 262 | } 263 | pub async fn set(&mut self, x: i32, y: i32) -> i32 { 264 | self.x += x; 265 | self.y += y; 266 | sleep(Duration::from_millis(1)).await; 267 | println!("{} {}", self.x, self.y); 268 | self.i += 1; 269 | self.i 270 | } 271 | } 272 | 273 | trait FooRunner { 274 | async fn set(&self, x: i32, y: i32) -> i32; 275 | async fn get(&self) -> (i32, i32, i32); 276 | async fn get_len<'a>(&'a self, b: &'a [u8]) -> usize; 277 | } 278 | 279 | impl FooRunner for Actor { 280 | async fn set(&self, x: i32, y: i32) -> i32 { 281 | self.inner_call(|inner| async move { inner.get_mut().set(x, y).await }).await 282 | } 283 | 284 | async fn get(&self) -> (i32, i32, i32) { 285 | self.inner_call(|inner| async move { inner.get().get() }).await 286 | } 287 | 288 | async fn get_len<'a>(&'a self, b: &'a [u8]) -> usize { 289 | self.inner_call(|_| async move { b.len() }).await 290 | } 291 | } 292 | 293 | let a_foo = Arc::new(Actor::new(Foo::default())); 294 | let b_foo = a_foo.clone(); 295 | let b = tokio::spawn(async move { 296 | for i in 0..100 { 297 | let x = b_foo.set(i - 1, i + 1).await; 298 | println!("b:{}", x); 299 | } 300 | }); 301 | 302 | let c_foo = a_foo.clone(); 303 | let c = tokio::spawn(async move { 304 | for i in 0..100 { 305 | let x = c_foo.set(i - 1, i + 1).await; 306 | println!("c:{}", x); 307 | } 308 | }); 309 | 310 | for i in 200..300 { 311 | let x = a_foo.set(i - 1, i + 1).await; 312 | println!("a:{}", x); 313 | } 314 | 315 | try_join!(b, c)?; 316 | 317 | assert_eq!((300, 34550, 35150), a_foo.get().await); 318 | 319 | let buff = vec![1, 2, 3, 4, 5]; 320 | let x = { a_foo.get_len(&buff[..]).await }; 321 | assert_eq!(buff.len(), x); 322 | 323 | Ok(()) 324 | } 325 | -------------------------------------------------------------------------------- /tests/test_rw.rs: -------------------------------------------------------------------------------- 1 | use anyhow::Result; 2 | use aqueue::{RwModel, RwQueue}; 3 | 4 | use futures_util::try_join; 5 | use std::cell::Cell; 6 | use std::sync::Arc; 7 | use std::time::Instant; 8 | use tokio::time::{sleep, Duration}; 9 | 10 | static mut VALUE: u64 = 0; 11 | 12 | #[tokio::test] 13 | async fn test_base() -> Result<()> { 14 | let queue = Arc::new(RwQueue::new()); 15 | 16 | let a_queue = queue.clone(); 17 | tokio::spawn(async move { 18 | let x = a_queue 19 | .write_run( 20 | |_| async move { 21 | println!("a"); 22 | //delay_for(Duration::from_secs(1)).await; 23 | 1 24 | }, 25 | &mut (), 26 | ) 27 | .await; 28 | 29 | println!("{:?}", x); 30 | }) 31 | .await?; 32 | 33 | let a_queue = queue.clone(); 34 | tokio::spawn(async move { 35 | for i in 0..100 { 36 | a_queue 37 | .read_run( 38 | |_| async move { 39 | println!("b:{}", i); 40 | () 41 | }, 42 | &(), 43 | ) 44 | .await; 45 | } 46 | }) 47 | .await?; 48 | 49 | sleep(Duration::from_secs(2)).await; 50 | 51 | let start = Instant::now(); 52 | let mut v = 0u64; 53 | for mut i in 0..10000000 { 54 | v = queue 55 | .write_run( 56 | |x| async move { 57 | unsafe { 58 | VALUE += *x; 59 | VALUE 60 | } 61 | }, 62 | &mut i, 63 | ) 64 | .await; 65 | } 66 | 67 | println!("{} {}", start.elapsed().as_secs_f32(), v); 68 | 69 | assert_eq!(v, 49999995000000); 70 | 71 | Ok(()) 72 | } 73 | 74 | #[tokio::test] 75 | async fn test_struct() -> Result<()> { 76 | #[async_trait::async_trait] 77 | trait IFoo { 78 | async fn run(&self, x: i32, y: i32) -> i32; 79 | fn get_count(&self) -> i32; 80 | } 81 | pub struct Foo { 82 | count: Cell, 83 | } 84 | 85 | unsafe impl Sync for Foo {} 86 | #[async_trait::async_trait] 87 | impl IFoo for Foo { 88 | async fn run(&self, x: i32, y: i32) -> i32 { 89 | self.count.set(self.count.get() + 1); 90 | x + y 91 | } 92 | 93 | fn get_count(&self) -> i32 { 94 | self.count.get() 95 | } 96 | } 97 | 98 | pub struct MakeActorIFoo { 99 | inner: Arc, 100 | queue: RwQueue, 101 | } 102 | 103 | impl MakeActorIFoo { 104 | pub fn from(x: Foo) -> MakeActorIFoo { 105 | MakeActorIFoo { 106 | inner: Arc::new(x), 107 | queue: RwQueue::new(), 108 | } 109 | } 110 | } 111 | 112 | #[async_trait::async_trait] 113 | impl IFoo for MakeActorIFoo { 114 | async fn run(&self, x: i32, y: i32) -> i32 { 115 | self.queue 116 | .read_run(|inner| async move { inner.run(x, y).await }, &self.inner.clone()) 117 | .await 118 | } 119 | 120 | fn get_count(&self) -> i32 { 121 | self.inner.get_count() 122 | } 123 | } 124 | 125 | let foo = Foo { count: Cell::new(0) }; 126 | let make = Arc::new(MakeActorIFoo::from(foo)); 127 | let x = make.run(1, 2).await; 128 | assert_eq!(x, 3); 129 | 130 | let begin = Instant::now(); 131 | let a_make = make.clone(); 132 | let a = tokio::spawn(async move { 133 | let start = Instant::now(); 134 | for i in 0..2000000 { 135 | a_make.run(i, i).await; 136 | } 137 | 138 | println!("a {} {}", start.elapsed().as_secs_f32(), a_make.inner.get_count()); 139 | }); 140 | 141 | let b_make = make.clone(); 142 | let b = tokio::spawn(async move { 143 | let start = Instant::now(); 144 | for i in 0..2000000 { 145 | b_make.run(i, i).await; 146 | } 147 | 148 | println!("b {} {}", start.elapsed().as_secs_f32(), b_make.inner.get_count()); 149 | }); 150 | 151 | let c = tokio::spawn(async move { 152 | let start = Instant::now(); 153 | for i in 0..2000000 { 154 | make.run(i, i).await; 155 | } 156 | println!("c {} {}", start.elapsed().as_secs_f32(), make.inner.get_count()); 157 | }); 158 | 159 | try_join!(a, b, c)?; 160 | 161 | println!("all secs:{}", begin.elapsed().as_secs_f32()); 162 | 163 | Ok(()) 164 | } 165 | 166 | #[tokio::test] 167 | async fn test_count() -> Result<()> { 168 | struct Foo { 169 | count: u64, 170 | data: String, 171 | } 172 | 173 | impl Foo { 174 | pub fn add_one(&mut self) { 175 | self.count += 1; 176 | self.data.push_str(&self.count.to_string()) 177 | } 178 | 179 | pub fn get_str(&self) -> String { 180 | self.data.clone() 181 | } 182 | } 183 | 184 | trait IFoo { 185 | async fn add_one(&self) -> Result<()>; 186 | async fn get_str(&self) -> Result; 187 | } 188 | 189 | impl IFoo for RwModel { 190 | async fn add_one(&self) -> Result<()> { 191 | self.call_mut(|mut inner| async move { 192 | inner.add_one(); 193 | Ok(()) 194 | }) 195 | .await 196 | } 197 | 198 | async fn get_str(&self) -> Result { 199 | self.call(|inner| async move { Ok(inner.get_str()) }).await 200 | } 201 | } 202 | 203 | let obj = Arc::new(RwModel::new(Foo { 204 | count: 0, 205 | data: "".to_string(), 206 | })); 207 | 208 | let mut vec = vec![]; 209 | for _ in 0..1000 { 210 | let p_obj = obj.clone(); 211 | vec.push(tokio::spawn(async move { 212 | for _ in 0..1000 { 213 | p_obj.add_one().await.unwrap(); 214 | } 215 | })); 216 | } 217 | 218 | for j in vec { 219 | j.await?; 220 | } 221 | 222 | let mut check = Foo { 223 | count: 0, 224 | data: "".to_string(), 225 | }; 226 | 227 | for _ in 0..1000000 { 228 | check.add_one(); 229 | } 230 | 231 | let str = obj.get_str().await?; 232 | assert_eq!(str, check.get_str()); 233 | 234 | Ok(()) 235 | } 236 | 237 | #[tokio::test] 238 | async fn test_string() -> Result<()> { 239 | let queue = Arc::new(RwQueue::new()); 240 | let str = 12345.to_string(); 241 | let len = queue.read_run(|x| async move { x.len() }, &str).await; 242 | assert_eq!(len, 5); 243 | struct Foo { 244 | i: i32, 245 | } 246 | let foo = Foo { i: 5 }; 247 | let len = queue.read_run(|x| async move { x.i }, &foo).await; 248 | assert_eq!(len, 5); 249 | 250 | Ok(()) 251 | } 252 | 253 | #[tokio::test] 254 | async fn test_actor() -> Result<()> { 255 | #[derive(Default)] 256 | struct Foo { 257 | i: i32, 258 | x: i32, 259 | y: i32, 260 | } 261 | 262 | impl Foo { 263 | pub fn get(&self) -> (i32, i32, i32) { 264 | (self.i, self.x, self.y) 265 | } 266 | pub async fn set(&mut self, x: i32, y: i32) -> i32 { 267 | self.x += x; 268 | self.y += y; 269 | sleep(Duration::from_millis(1)).await; 270 | println!("{} {}", self.x, self.y); 271 | self.i += 1; 272 | self.i 273 | } 274 | } 275 | 276 | trait FooRunner { 277 | async fn set(&self, x: i32, y: i32) -> i32; 278 | async fn get(&self) -> (i32, i32, i32); 279 | async fn get_len<'a>(&'a self, b: &'a [u8]) -> usize; 280 | } 281 | 282 | impl FooRunner for RwModel { 283 | async fn set(&self, x: i32, y: i32) -> i32 { 284 | self.call_mut(|mut inner| async move { inner.set(x, y).await }).await 285 | } 286 | 287 | async fn get(&self) -> (i32, i32, i32) { 288 | self.call(|inner| async move { inner.get() }).await 289 | } 290 | 291 | async fn get_len<'a>(&'a self, b: &'a [u8]) -> usize { 292 | self.call(|_| async move { b.len() }).await 293 | } 294 | } 295 | 296 | let a_foo = Arc::new(RwModel::new(Foo::default())); 297 | let b_foo = a_foo.clone(); 298 | let b = tokio::spawn(async move { 299 | for i in 0..100 { 300 | let x = b_foo.set(i - 1, i + 1).await; 301 | println!("b:{}", x); 302 | } 303 | }); 304 | 305 | let c_foo = a_foo.clone(); 306 | let c = tokio::spawn(async move { 307 | for i in 0..100 { 308 | let x = c_foo.set(i - 1, i + 1).await; 309 | println!("c:{}", x); 310 | } 311 | }); 312 | 313 | for i in 200..300 { 314 | let x = a_foo.set(i - 1, i + 1).await; 315 | println!("a:{}", x); 316 | } 317 | 318 | try_join!(b, c)?; 319 | 320 | assert_eq!((300, 34550, 35150), a_foo.get().await); 321 | 322 | let buff = vec![1, 2, 3, 4, 5]; 323 | let x = { a_foo.get_len(&buff[..]).await }; 324 | assert_eq!(buff.len(), x); 325 | 326 | Ok(()) 327 | } 328 | 329 | #[tokio::test] 330 | async fn test_rw_model() -> Result<()> { 331 | struct Foo { 332 | i: i32, 333 | } 334 | 335 | impl Foo { 336 | async fn get(&self) -> i32 { 337 | println!("get:{}", self.i); 338 | tokio::time::sleep(Duration::from_secs(1)).await; 339 | self.i 340 | } 341 | 342 | async fn set(&mut self, i: i32) { 343 | println!("set:{}", i); 344 | self.i = i; 345 | } 346 | } 347 | 348 | trait IFoo { 349 | async fn get(&self) -> i32; 350 | async fn set(&self, i: i32); 351 | } 352 | 353 | impl IFoo for RwModel { 354 | async fn get(&self) -> i32 { 355 | self.call(|inner| async move { inner.get().await }).await 356 | } 357 | 358 | async fn set(&self, i: i32) { 359 | self.call_mut(|mut inner| async move { inner.set(i).await }).await 360 | } 361 | } 362 | 363 | let foo = Arc::new(RwModel::new(Foo { i: 0 })); 364 | 365 | let mut joins = Vec::new(); 366 | for i in 0..30 { 367 | //Theoretically, it should be completed in 1 second 368 | //But adding sleep resulted in a long execution time 369 | //So RWModel is still only suitable for environments with more read and less write. 370 | tokio::time::sleep(Duration::from_millis(1)).await; 371 | let foo = foo.clone(); 372 | joins.push(tokio::spawn(async move { 373 | foo.get().await; 374 | foo.set(i).await; 375 | })) 376 | } 377 | 378 | for join in joins { 379 | join.await?; 380 | } 381 | 382 | Ok(()) 383 | } 384 | -------------------------------------------------------------------------------- /tests/test_semaphore.rs: -------------------------------------------------------------------------------- 1 | use aqueue::{PCModel, SemaphoreQueue}; 2 | use std::sync::Arc; 3 | 4 | #[tokio::test] 5 | async fn test_base() { 6 | let queue = Arc::new(SemaphoreQueue::new(5)); 7 | let mut tasks = vec![]; 8 | let now = std::time::Instant::now(); 9 | for i in 0..10 { 10 | let queue = queue.clone(); 11 | tasks.push(tokio::spawn(async move { 12 | let g = queue 13 | .run( 14 | |x| async move { 15 | println!("{}: acquired", x); 16 | tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; 17 | println!("{i} run end"); 18 | x 19 | }, 20 | i, 21 | ) 22 | .await; 23 | g 24 | })) 25 | } 26 | 27 | for task in tasks { 28 | let i = task.await.unwrap(); 29 | println!("{i} finished"); 30 | } 31 | 32 | assert!(now.elapsed().as_secs() >= 2 && now.elapsed().as_secs() < 3); 33 | } 34 | 35 | #[tokio::test] 36 | async fn test_pc_model() { 37 | struct Foo; 38 | 39 | impl Foo { 40 | pub async fn run(&self, x: i32) -> i32 { 41 | println!("pc mode {x}: acquired"); 42 | tokio::time::sleep(tokio::time::Duration::from_secs(1)).await; 43 | println!("pc mode {x}: run end"); 44 | x 45 | } 46 | } 47 | 48 | trait IFoo { 49 | async fn pc_run(&self, x: i32) -> i32; 50 | } 51 | 52 | impl IFoo for PCModel { 53 | async fn pc_run(&self, x: i32) -> i32 { 54 | self.call(|inner| async move { inner.run(x).await }).await 55 | } 56 | } 57 | 58 | let foo = Arc::new(PCModel::new(Foo, 5)); 59 | let mut tasks = vec![]; 60 | 61 | let now = std::time::Instant::now(); 62 | for i in 0..10 { 63 | let foo = foo.clone(); 64 | tasks.push(tokio::spawn(async move { foo.pc_run(i).await })) 65 | } 66 | 67 | for task in tasks { 68 | let i = task.await.unwrap(); 69 | println!("pc mode {i}: finished"); 70 | } 71 | 72 | assert!(now.elapsed().as_secs() >= 2 && now.elapsed().as_secs() < 3); 73 | 74 | println!("--------------------------------------"); 75 | 76 | let mut tasks = vec![]; 77 | 78 | let now = std::time::Instant::now(); 79 | for i in 0..10 { 80 | tokio::time::sleep(tokio::time::Duration::from_millis(100)).await; 81 | let foo = foo.clone(); 82 | tasks.push(tokio::spawn(async move { foo.pc_run(i).await })) 83 | } 84 | 85 | for task in tasks { 86 | let i = task.await.unwrap(); 87 | println!("pc mode {i}: finished"); 88 | } 89 | 90 | assert!(now.elapsed().as_secs() >= 2 && now.elapsed().as_secs() < 3); 91 | } 92 | --------------------------------------------------------------------------------