Tokio 비동기 녹슨 기초 지식
소개하다.
비동기 코드가 지금 없는 곳이 없습니다.API/백엔드 프로그램과 같은 확장이 필요한 모든 것을 쓸 때, 이것은 기본적으로 필수적이다.Rust의 비동기 코드를 처리하는 방법은 다르지만 Tokio라고 부르는 가장 유행하는 쪽지 상자를 사용할 것입니다.결국 여러 요청을 동시에 처리할 수 있는 매우 간단한 API를 만들 것입니다.우리 시작합시다!
마지막 코드는 여기에서 찾을 수 있습니다: Tokio tutorial Github repo.
단순 비동기
우선 임무를 수행하는 기본 프로그램을 만듭니다.프로젝트를 만들려면 다음과 같이 하십시오.
$ cargo new tokio-tutorial
$ cd tokio-tutorial
이 임무에 대해 우리는 단지 의존항 하나만 필요로 한다.그래서 Cargo.toml
를 열고 다음과 같이 추가합니다.[dependencies]
tokio = {version = "1.14.0", features = ["full"]}
이제 src/main.rs
로 이동하여 내용을 다음으로 바꿉니다.#[tokio::main]
async fn main() {
let task = tokio::spawn(async {
println!("Hello, rust!");
});
task.await.unwrap();
}
이것이 바로 cargo run
간단한 비동기 작업을 실행하는 데 필요한 전부입니다!이 장의 전체 코드on my Github를 찾을 수 있습니다.
물론 이 예는 Tokio가 실행될 때의 진정한 위력을 보여주지 않았기 때문에 더 유용한 예로 넘어가도록 하겠습니다.
저축 잔액 API
좋습니다. 다른 업무 목록 API를 만드는 것을 피하기 위해서, 저축 잔액 API를 더 간단하게 할 것입니다.목표는 간단합니다. GET와 POST로 균형을 관리하는 두 가지 방법을 보여 드리겠습니다.GET는 현재 값을 반환하고 POST는 가/감 작업을 수행합니다.만약 네가 녹슨 책을 뒤적거린다면, 너는 우연히 발견할 수 있을 것이다. Multithreaded Web Server project이것은 당신의 머리를 라인을 둘러싸게 하는 아주 좋은 출발점이지만, 대량의 샘플 코드 (수동 라인 관리 등) 가 필요하다.이것이 바로 Tokio의 용무지이다.
제1반응
우리는 전송 요청을 감청하는 간단한 서버부터 시작할 것이다.
main.rs
의 컨텐트를 다음으로 바꾸려면 다음과 같이 하십시오.use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream};
#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:8181").await.unwrap();
loop {
let (stream, _) = listener.accept().await.unwrap();
handle_connection(stream).await;
}
}
async fn handle_connection(mut stream: TcpStream) {
let contents = "{\"balance\": 0.00}";
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
contents.len(),
contents
);
stream.write(response.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
}
그것을 실행한 다음 브라우저에서 http://127.0.0.1:8181 로 이동하여 서버의 첫 번째 응답을 보십시오.몇 가지 코드 설명:예를 들어, 우리의 코드는 한 번에 하나의 요청만 처리한다.그러면 우리는 어떻게 그것으로 하여금 연결을 동시에 처리하게 합니까?아주 간단합니다.
handle_connection()
를 tokio::spawn
함수에 포장하기만 하면 됩니다.tokio::spawn(async move {
handle_connection(stream).await;
});
이렇게!이제 여러 연결을 한 번에 처리할 수 있습니다!지금까지의 코드Can be found on GitHub here
가져오기 및 게시
우리가 강좌의 마지막 부분에 들어간다. 균형치를 수정하기 전에, 우리는 우리가 균형을 읽고 변경할 수 있도록 확보해야 한다.
간단하게 보기 위해서 우리는 두 가지 장면이 있을 것이다.
GET 요청이 감지되면 잔액이 반환됩니다.
POST 메서드가 라우팅에서 값(최대 10자)을 읽고 잔액을 업데이트하고 반환합니다.
새로운 모델
handle_connection
의 모양은 다음과 같습니다.async fn handle_connection(mut stream: TcpStream) {
// Read the first 16 characters from the incoming stream.
let mut buffer = [0; 16];
stream.read(&mut buffer).await.unwrap();
// First 4 characters are used to detect HTTP method
let method_type = match str::from_utf8(&buffer[0..4]) {
Ok(v) => v,
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
};
let contents = match method_type {
"GET " => {
// todo: return real balance
format!("{{\"balance\": {}}}", 0.0)
}
"POST" => {
// Take characters after 'POST /' until whitespace is detected.
let input: String = buffer[6..16]
.iter()
.take_while(|x| **x != 32u8)
.map(|x| *x as char)
.collect();
let balance_update = input.parse::<f32>().unwrap();
// todo: add balance update handling
format!("{{\"balance\": {}}}", balance_update)
}
_ => {
panic!("Invalid HTTP method!")
}
};
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
contents.len(),
contents
);
stream.write(response.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
}
전송된 요청에서 n 개의 문자를 읽고 선택한 동작을 실행하는 것이 우리의 생각입니다.프레젠테이션의 목적과 단순성을 위해 최대 10자까지 입력할 것입니다.지금 그것을 실행해 보세요. 응답이 선택한 방법에 따라 어떻게 변화하는지 보십시오.예제 cURL 명령:
curl --request POST 'http://127.0.0.1:8181/-12.98'
평형
지금까지, 우리의 처리 프로그램은 하드코딩의 결과를 되돌려 주었다.호출 사이에서 값을 유지할 변수를 도입합시다.우리의 균형 변수는 작업과 잠재적인 라인 사이에서 공유되기 때문에 이를 지원하기 위해
Arc<Mutex<_>>
에 포장되어 있습니다.Arc<>
는 여러 작업에서 변수를 동시에 인용할 수 있도록 허용한다Mutex<>
는 보호로서 한 번에 한 작업만 변수를 변경할 수 있도록 확보한다(다른 작업은 그것들의 차례를 기다려야 한다).다음은 잔액 업데이트의 전체 코드입니다.새 행의 주석을 보려면 다음과 같이 하십시오.
use std::str;
use std::sync::{Arc, Mutex, MutexGuard};
use tokio::io::AsyncReadExt;
use tokio::io::AsyncWriteExt;
use tokio::net::{TcpListener, TcpStream};
#[tokio::main]
async fn main() {
// create balance wrapped in Arc and Mutex for cross thread safety
let balance = Arc::new(Mutex::new(0.00f32));
let listener = TcpListener::bind("127.0.0.1:8181").await.unwrap();
loop {
let (stream, _) = listener.accept().await.unwrap();
// Clone the balance Arc and pass it to handler
let balance = balance.clone();
tokio::spawn(async move {
handle_connection(stream, balance).await;
});
}
}
async fn handle_connection(mut stream: TcpStream, balance: Arc<Mutex<f32>>) {
// Read the first 16 characters from the incoming stream.
let mut buffer = [0; 16];
stream.read(&mut buffer).await.unwrap();
// First 4 characters are used to detect HTTP method
let method_type = match str::from_utf8(&buffer[0..4]) {
Ok(v) => v,
Err(e) => panic!("Invalid UTF-8 sequence: {}", e),
};
let contents = match method_type {
"GET " => {
// before using balance we need to lock it.
format!("{{\"balance\": {}}}", balance.lock().unwrap())
}
"POST" => {
// Take characters after 'POST /' until whitespace is detected.
let input: String = buffer[6..16]
.iter()
.take_while(|x| **x != 32u8)
.map(|x| *x as char)
.collect();
let balance_update = input.parse::<f32>().unwrap();
// acquire lock on our balance and update the value
let mut locked_balance: MutexGuard<f32> = balance.lock().unwrap();
*locked_balance += balance_update;
format!("{{\"balance\": {}}}", locked_balance)
}
_ => {
panic!("Invalid HTTP method!")
}
};
let response = format!(
"HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\n\r\n{}",
contents.len(),
contents
);
stream.write(response.as_bytes()).await.unwrap();
stream.flush().await.unwrap();
}
잔액 자물쇠를 가져오고 있지만 수동으로 잠금을 풀 필요는 없습니다.일단 MutexGuard
가 되돌아온 lock()
가 범위를 초과하면 자물쇠는 자동으로 제거됩니다.우리의 경우, 이것은 우리가 응답 내용을 준비한 후이다.현재, 우리는 프로그램을 실행할 준비가 되어 있으며, 우리가 정확한 균형 응답을 받았는지 테스트할 준비가 되어 있다.예제 cURL 명령:
curl --request POST 'http://127.0.0.1:8181/150.50'
다음은 연습입니다: lock을 사용하여 코드의 실행에 어떻게 영향을 미치는지 이해하려면 지연을 추가하십시오 (보십시오 tokio::timer::Delay
). 자물쇠를 얻은 후에 지연이 충분하면 여러 개의 API 호출을 할 수 있습니다.결론
보시다시피 Rust에서 비동기적인 조작을 처리하는 프로그램을 만드는 것이 Tokio runtime보다 쉽습니다.물론 API에 대해서는 Actix, 로켓, Warp 등 웹 프레임워크를 사용하지만, 어떻게 엔진 뚜껑에서 작동하는지 더 잘 이해하기를 바랍니다.
마지막 코드는 여기에서 찾을 수 있습니다: Tokio tutorial Github repo.
나는 당신이 이 강좌를 좋아하길 희망합니다. 만약 어떤 건의/문제가 있으면 언제든지 아래에서 평론을 발표하십시오.
다음까지 읽어주셔서 감사합니다!
Reference
이 문제에 관하여(Tokio 비동기 녹슨 기초 지식), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/jbarszczewski/basics-of-asynchronous-rust-with-tokio-34fn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)