mirror of
https://github.com/actix/actix-website
synced 2024-11-23 16:31:08 +01:00
Add explanations regarding actix-web's multithreaded server model (#150)
* Add explanations regarding actix-web's multithreaded server model * Improve phrasing * Typo fix Co-authored-by: Yuki Okushi <huyuumi.dev@gmail.com>
This commit is contained in:
parent
c1a8103cbc
commit
8c8de9f7fb
@ -31,18 +31,53 @@ Following example shows how to start http server in separate thread.
|
||||
|
||||
## Multi-threading
|
||||
|
||||
`HttpServer` automatically starts a number of http workers, by default this number is
|
||||
`HttpServer` automatically starts a number of http *workers*, by default this number is
|
||||
equal to number of logical CPUs in the system. This number can be overridden with the
|
||||
[`HttpServer::workers()`][workers] method.
|
||||
|
||||
{{< include-example example="server" file="workers.rs" section="workers" >}}
|
||||
|
||||
The server creates a separate application instance for each created worker. Application state
|
||||
is not shared between threads. To share state, `Arc` could be used.
|
||||
Once the workers are created, they each receive a separate *application* instance to handle
|
||||
requests. Application state is not shared between the threads, and handlers are free to manipulate
|
||||
their copy of the state with no concurrency concerns.
|
||||
|
||||
> Application state does not need to be `Send` or `Sync`, but application
|
||||
factory must be `Send` + `Sync`.
|
||||
|
||||
To share state between worker threads, use an `Arc`. Special care should be taken once sharing and
|
||||
synchronization are introduced. In many cases, performance costs are inadvertently introduced as a
|
||||
result of locking the shared state for modifications.
|
||||
|
||||
In some cases these costs can be alleviated using more efficient locking strategies, for example
|
||||
using [read/write locks](https://doc.rust-lang.org/std/sync/struct.RwLock.html) instead of
|
||||
[mutexes](https://doc.rust-lang.org/std/sync/struct.Mutex.html) to achieve non-exclusive locking,
|
||||
but the most performant implementations often tend to be ones in which no locking occurs at all.
|
||||
|
||||
Since each worker thread processes its requests sequentially, handlers which block the current
|
||||
thread will cause the current worker to stop processing new requests:
|
||||
|
||||
```rust
|
||||
fn my_handler() -> impl Responder {
|
||||
std::thread::sleep(Duration::from_secs(5)); // <-- Bad practice! Will cause the current worker thread to hang!
|
||||
"response"
|
||||
}
|
||||
```
|
||||
For this reason, any long, non-cpu-bound operation (e.g. I/O, database operations, etc.) should be
|
||||
expressed as futures or asynchronous functions. Async handlers get executed concurrently by worker
|
||||
threads and thus don't block execution:
|
||||
|
||||
```rust
|
||||
async fn my_handler() -> impl Responder {
|
||||
tokio::time::delay_for(Duration::from_secs(5)).await; // <-- Ok. Worker thread will handle other requests here
|
||||
"response"
|
||||
}
|
||||
```
|
||||
|
||||
The same limitation applies to extractors as well. When a handler function receives an argument
|
||||
which implements `FromRequest`, and that implementation blocks the current thread, the worker thread
|
||||
will block when running the handler. Special attention must be given when implementing extractors
|
||||
for this very reason, and they should also be implemented asynchronously where needed.
|
||||
|
||||
## SSL
|
||||
|
||||
There are two features for the ssl server: `rustls` and `openssl`. The `rustls` feature is for
|
||||
|
Loading…
Reference in New Issue
Block a user