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.)