diff --git a/README.md b/README.md index 3effbf95..cb0c55d4 100644 --- a/README.md +++ b/README.md @@ -8,25 +8,33 @@ [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "Percentage of issues still open") -The `open-coroutine` is a simple, efficient and generic stackfull-coroutine library, you can use this as a performance replacement for IO thread pools. +The `open-coroutine` is a simple, efficient and generic stackfull-coroutine library, you can use this as a performance +replacement for IO thread pools, see [why better](core/docs/en/why-better.md). English | [中文](README_ZH.md) ## 🚀 Features -- [x] Preemptive(`not supported in windows`): even if the coroutine enters a dead loop, it can still be seized, see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/preemptive.rs); -- [x] Hook: you are free to use most of the slow syscall in coroutine, see supported syscall on [unix](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/unix.rs)/[windows](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/windows.rs); -- [x] Scalable: the size of the coroutine stack supports unlimited expansion without the cost of copying stack, and immediately shrinks to the original size after use, see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/scalable_stack.rs); -- [x] io_uring(`only in linux`): supports and is compatible with io_uring in terms of local file IO and network IO. If it's not supported on your system, it will fall back to non-blocking IO; +- [x] Preemptive(`not supported in windows`): even if the coroutine enters a dead loop, it can still be seized, + see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/preemptive.rs); +- [x] Hook: you are free to use most of the slow syscall in coroutine, see supported syscall + on [unix](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/unix.rs)/[windows](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/windows.rs); +- [x] Scalable: the size of the coroutine stack supports unlimited expansion without the cost of copying stack, and + immediately shrinks to the original size after use, + see [example](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/scalable_stack.rs); +- [x] io_uring(`only in linux`): supports and is compatible with io_uring in terms of local file IO and network IO. If + it's not supported on your system, it will fall back to non-blocking IO; - [x] Priority: support custom task priority, note that coroutine priority is not open to users; - [x] Work Steal: internally using a lock free work steal queue; -- [x] Compatibility: the implementation of open-coroutine is no async, but it is compatible with async, which means you can use this crate in `tokio/async-std/smol/...`; +- [x] Compatibility: the implementation of open-coroutine is no async, but it is compatible with async, which means you + can use this crate in `tokio/async-std/smol/...`; - [x] Platforms: running on Linux, macOS and Windows; ## 🕊 Roadmap - [ ] add docs; -- [ ] add performance [benchmark](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview); +- [ ] add + performance [benchmark](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview); - [ ] cancel coroutine/task; - [ ] add metrics; - [ ] add synchronization toolkit; @@ -79,7 +87,7 @@ graph TD subgraph open-coroutine end hook -->|depends on| core - open-coroutine -->|depends on| hook + open-coroutine -->|link| hook open-coroutine -->|depends on| macros end subgraph OperationSystem @@ -179,11 +187,12 @@ fn main() { ## ⚓ Learn More - [Coroutine Overview](core/docs/en/coroutine.md) +- [Scalable Stack Overview](core/docs/en/scalable-stack.md) - [Monitor Overview](core/docs/en/monitor.md) [我有故事,你有酒吗?](https://github.com/acl-dev/open-coroutine-docs) -## 🙏 Credits +## 👍 Credits This crate was inspired by the following projects: @@ -194,3 +203,10 @@ This crate was inspired by the following projects: - [monoio](https://github.com/bytedance/monoio) - [compio](https://github.com/compio-rs/compio) - [may](https://github.com/Xudong-Huang/may) + +Thanks to those who have provided assistance: + +![Amanieu](https://images.weserv.nl/?url=avatars.githubusercontent.com/Amanieu?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![bjorn3](https://images.weserv.nl/?url=avatars.githubusercontent.com/bjorn3?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![workingjubilee](https://images.weserv.nl/?url=avatars.githubusercontent.com/workingjubilee?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![Noratrieb](https://images.weserv.nl/?url=avatars.githubusercontent.com/Noratrieb?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) diff --git a/README_ZH.md b/README_ZH.md index e0383fb5..03643ad6 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -8,15 +8,18 @@ [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "解决issue的平均时间") [![Percentage of issues still open](http://isitmaintained.com/badge/open/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "仍未关闭issue的百分比") -`open-coroutine`是一个简单、高效、通用的有栈协程库,您可以将其用作IO线程池的性能替代。 +`open-coroutine`是一个简单、高效、通用的有栈协程库,您可以将其用作IO线程池的性能替代,查看[为什么更好](core/docs/en/why-better.md). [English](README.md) | 中文 ## 🚀 当前特性 -- [x] 抢占调度(`不支持windows`): 即使协程进入死循环,它仍能被抢占,查看[例子](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/preemptive.rs); -- [x] Hook: 您可以在协程中自由使用大多数慢系统调用,查看支持的系统调用[unix](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/unix.rs)/[windows](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/windows.rs); -- [x] 可伸缩栈: 协程栈的大小支持无限制扩容而没有复制堆栈的开销,查看[例子](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/scalable_stack.rs); +- [x] 抢占调度(`不支持windows`): + 即使协程进入死循环,它仍能被抢占,查看[例子](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/preemptive.rs); +- [x] Hook: + 您可以在协程中自由使用大多数慢系统调用,查看支持的系统调用[unix](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/unix.rs)/[windows](https://github.com/acl-dev/open-coroutine/blob/master/hook/src/syscall/windows.rs); +- [x] 可伸缩栈: + 协程栈的大小支持无限制扩容而没有复制堆栈的开销,查看[例子](https://github.com/loongs-zhang/open-coroutine/blob/master/open-coroutine/examples/scalable_stack.rs); - [x] io_uring(`只支持linux`): 在本地文件IO和网络IO方面支持并兼容io_uring。如果您的系统不支持,它将回退到NIO; - [x] 优先级: 支持自定义任务优先级,注意协程优先级未对用户开放; - [x] 任务窃取: 内部使用无锁任务窃取队列; @@ -26,7 +29,8 @@ ## 🕊 未来计划 - [ ] 完善文档; -- [ ] 增加性能[基准测试](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview); +- [ ] + 增加性能[基准测试](https://github.com/TechEmpower/FrameworkBenchmarks/wiki/Project-Information-Framework-Tests-Overview); - [ ] 取消协程/任务; - [ ] 增加性能指标; - [ ] 增加并发工具包; @@ -79,7 +83,7 @@ graph TD subgraph open-coroutine end hook -->|depends on| core - open-coroutine -->|depends on| hook + open-coroutine -->|link| hook open-coroutine -->|depends on| macros end subgraph OperationSystem @@ -153,7 +157,7 @@ fn main() { } ``` -### 扩容栈 +### 可伸缩栈 ```rust #[open_coroutine::main] @@ -183,7 +187,7 @@ fn main() { [我有故事,你有酒吗?](https://github.com/acl-dev/open-coroutine-docs) -## 🙏 鸣谢 +## 👍 鸣谢 这个crate的灵感来自以下项目: @@ -193,4 +197,11 @@ fn main() { - [stacker](https://github.com/rust-lang/stacker) - [monoio](https://github.com/bytedance/monoio) - [compio](https://github.com/compio-rs/compio) -- [may](https://github.com/Xudong-Huang/may) \ No newline at end of file +- [may](https://github.com/Xudong-Huang/may) + +感谢那些提供帮助的人: + +![Amanieu](https://images.weserv.nl/?url=avatars.githubusercontent.com/Amanieu?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![bjorn3](https://images.weserv.nl/?url=avatars.githubusercontent.com/bjorn3?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![workingjubilee](https://images.weserv.nl/?url=avatars.githubusercontent.com/workingjubilee?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) +![Noratrieb](https://images.weserv.nl/?url=avatars.githubusercontent.com/Noratrieb?v=4&h=75&w=75&fit=cover&mask=circle&maxage=7d) diff --git a/core/docs/en/coroutine.md b/core/docs/en/coroutine.md index fc4e7d33..f8a5ab23 100644 --- a/core/docs/en/coroutine.md +++ b/core/docs/en/coroutine.md @@ -65,7 +65,8 @@ The above is excerpted from [corosensei](https://github.com/Amanieu/corosensei). | limitations | ✅ Few | ❌ Many | In general, if the requirements for resource utilization and switching performance are not very strict, using a -stackfull approach would be more convenient and the code would be easier to maintain. +stackfull approach would be more convenient and the code would be easier to maintain. So, `open-coroutine` chooses the +stackfull coroutine. ## State in open-coroutine diff --git a/core/docs/en/overview.md b/core/docs/en/overview.md index e7e47029..e7d0081a 100644 --- a/core/docs/en/overview.md +++ b/core/docs/en/overview.md @@ -1,4 +1,10 @@ -## open-coroutine overview +--- +title: open-coroutine Overview +date: 2025-01-10 08:24:00 +author: loongs-zhang +--- + +# open-coroutine overview [![crates.io](https://img.shields.io/crates/v/open-coroutine.svg)](https://crates.io/crates/open-coroutine) [![docs.rs](https://img.shields.io/badge/docs-release-blue)](https://docs.rs/open-coroutine) @@ -8,12 +14,14 @@ [![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "Average time to resolve an issue") [![Percentage of issues still open](http://isitmaintained.com/badge/open/acl-dev/open-coroutine.svg)](http://isitmaintained.com/project/acl-dev/open-coroutine "Percentage of issues still open") -The `open-coroutine` is a simple, efficient and generic stackfull-coroutine library, you can use this as a performance replacement for IO thread pools. +The `open-coroutine` is a simple, efficient and generic stackfull-coroutine library, you can use this as a performance +replacement for IO thread pools, see [why better](../en/why-better.md). [//]: # (todo 增加英文版本的文档) + - [Background](../../../docs/cn/background.md) -- [Why rust](../../../docs/cn/why-rust.md) -- [Why better]() +- [Why Rust](../../../docs/cn/why-rust.md) +- [Why Better](../en/why-better.md) - [Quick Start](../../../README.md) - [Coroutine Overview](../en/coroutine.md) - [Scalable Stack Overview](../en/scalable-stack.md) diff --git a/core/docs/en/why-better.md b/core/docs/en/why-better.md new file mode 100644 index 00000000..71ac1ac3 --- /dev/null +++ b/core/docs/en/why-better.md @@ -0,0 +1,114 @@ +--- +title: Why Better +date: 2025-01-10 08:28:00 +author: loongs-zhang +--- + +# Why Better + +## Syscall will not block + +Firstly, let's take a look at how thread collaborate with syscall. + +```mermaid +sequenceDiagram + Actor User Thread + participant Operation System + + User Thread ->>+ User Thread: execute + alt User Thread blocked + User Thread ->>+ Operation System: slow syscall + Operation System ->> User Thread: return + end + User Thread ->>+ User Thread: execute +``` + +If the syscall is a slow syscall, such as `accept` without setting non-blocking, the thread will be blocked for a long +time and unable to do anything until the OS returns. Now, let's take a look at how open-coroutine collaborate with +syscall. + +```mermaid +sequenceDiagram + Actor EventLoop Thread + participant Coroutine1 + participant Coroutine2 + participant Hooked Syscall + participant Operation System + + EventLoop Thread ->>+ Coroutine1: schedule + alt Coroutine1 blocked logically + Coroutine1 ->>+ Hooked Syscall: slow syscall + Hooked Syscall ->>+ Operation System: fast syscall + Operation System ->> Hooked Syscall: return errno + Hooked Syscall ->> Coroutine1: suspend the coroutine for a period of time + end + Coroutine1 ->>+ EventLoop Thread: suspended + EventLoop Thread ->>+ Coroutine2: schedule + alt Coroutine2 blocked logically + Coroutine2 ->>+ Hooked Syscall: slow syscall + Hooked Syscall ->>+ Operation System: fast syscall + Operation System ->> Hooked Syscall: return + Hooked Syscall ->> Coroutine2: return + end + Coroutine2 ->>+ EventLoop Thread: return + EventLoop Thread ->>+ Coroutine1: schedule + alt Coroutine1 blocked logically + Coroutine1 ->>+ Hooked Syscall: resume from the last pause + Hooked Syscall ->>+ Operation System: fast syscall + Operation System ->> Hooked Syscall: return + Hooked Syscall ->> Coroutine1: return + end + Coroutine1 ->>+ EventLoop Thread: return + EventLoop Thread ->>+ EventLoop Thread: schedule other coroutines +``` + +As you can see, `Hooked Syscall` converts `slow syscall` to `fast syscall`. In this way, although the `EventLoop Thread` +will still be blocked when executing syscall, the blocking time is very short. Therefore, compared to the thread model, +`EventLoop Thread` can do more things in the same amount of time. + +## Heavy computing will not block + +Secondly, let's take a look at how threads handle heavy computations. + +```mermaid +sequenceDiagram + Actor User Thread + + alt User Thread gets stuck in a loop + User Thread ->>+ User Thread: execute loop + end +``` + +Just like syscall above, thread will always block in the loop. Then, let's take a look at how open-coroutine handle +heavy computations. + +```mermaid +sequenceDiagram + Actor EventLoop Thread + participant Coroutine1 + participant Coroutine2 + participant Monitor + + EventLoop Thread ->>+ Coroutine1: schedule + alt Coroutine1 enters loop + Coroutine1 ->>+ Coroutine1: execute loop for a period of time + Monitor ->> Coroutine1: suspend the coroutine + end + Coroutine1 ->>+ EventLoop Thread: suspended + EventLoop Thread ->>+ Coroutine2: schedule + alt Coroutine2 enters loop + Coroutine2 ->>+ Coroutine2: execute loop for a period of time + Monitor ->> Coroutine1: suspend the coroutine + end + Coroutine2 ->>+ EventLoop Thread: suspended + EventLoop Thread ->>+ Coroutine1: schedule + alt Coroutine1 enters loop + Coroutine1 ->>+ Coroutine1: resume from the last pause + end + Coroutine1 ->>+ EventLoop Thread: return + EventLoop Thread ->>+ EventLoop Thread: schedule other coroutines +``` + +`Monitor` will monitor the execution of coroutines, and once it found that the execution time of a coroutine is too +long, it will force the coroutine to suspend. So now, we can even use just one `EventLoop Thread` to execute multiple +loops, which cannot be achieved under the single threaded model.