似乎无法#[tokio-test]在 Rust 文档测试中用于测试异步函数?
现在,我必须编写一个异步主函数,并用它来标记它#[tokio-main]并调用test_fn().await它,以让一些异步函数在cargo test --doc.
是否还有其他更好的方法来允许文档测试像普通测试功能一样运行,例如使用#[tokio-test]?另外,如果标签#[tokio-test]可以在文档中显示,那就太好了,这样用户就可以复制文档并直接在项目中将其用作测试。(这可能可以像这样完成##[tokio-test]?)
当运行这样的代码时:
use futures::executor;
...
pub fn store_temporary_password(email: &str, password: &str) -> Result<(), Box<dyn Error>> {
let client = DynamoDbClient::new(Region::ApSoutheast2);
...
let future = client.put_item(input);
executor::block_on(future)?; <- crashes here
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
我收到错误:
thread '<unnamed>' panicked at 'there is no reactor running, must be called from the context of a Tokio 1.x runtime
Run Code Online (Sandbox Code Playgroud)
我的 main 具有 tokio 注释,因为它应该是:
#[tokio::main]
async fn main() {
...
Run Code Online (Sandbox Code Playgroud)
我的 Cargo.toml 看起来像:
[dependencies]
...
futures = { version="0", features=["executor"] }
tokio = "1"
Run Code Online (Sandbox Code Playgroud)
我的 cars.lock 显示我只有 futures …
我能够继续实现我的异步 udp 服务器。但是,此错误出现两次,因为我的变量数据的类型*mut u8不是Send:
error: future cannot be sent between threads safely
help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut u8`
note: captured value is not `Send`
Run Code Online (Sandbox Code Playgroud)
和代码(MRE):
use std::error::Error;
use std::time::Duration;
use std::env;
use tokio::net::UdpSocket;
use tokio::{sync::mpsc, task, time}; // 1.4.0
use std::alloc::{alloc, Layout};
use std::mem;
use std::mem::MaybeUninit;
use std::net::SocketAddr;
const UDP_HEADER: usize = 8;
const IP_HEADER: usize = 20;
const AG_HEADER: usize = 4;
const MAX_DATA_LENGTH: usize = (64 …Run Code Online (Sandbox Code Playgroud) 我不确定它是否tokio类似于 Javascript 中的事件循环,也是一个非阻塞运行时,或者它是否可以用于以类似的方式工作。以我的理解,tokio是 Rust 中 future 的运行时。因此,它必须实现某种用户态线程或任务,这可以通过事件循环(至少部分)来调度新任务来实现。
我们来看下面的 Javascript 代码:
console.log('hello1');
setTimeout(() => console.log('hello2'), 0);
console.log('hello3');
setTimeout(() => console.log('hello4'), 0);
console.log('hello5');
Run Code Online (Sandbox Code Playgroud)
输出将是
hello1
hello3
hello5
hello2
hello4
Run Code Online (Sandbox Code Playgroud)
我怎样才能在东京做到这一点?tokio 总体上是这样工作的吗?我尝试了以下代码
async fn set_timeout(f: impl Fn(), ms: u64) {
tokio::time::sleep(tokio::time::Duration::from_millis(ms)).await;
f()
}
#[tokio::main]
async fn main() {
println!("hello1");
tokio::spawn(async {set_timeout(|| println!("hello2"), 0)}).await;
println!("hello3");
tokio::spawn(async {set_timeout(|| println!("hello4"), 0)}).await;
println!("hello5");
}
Run Code Online (Sandbox Code Playgroud)
输出只是
hello1
hello3
hello5
Run Code Online (Sandbox Code Playgroud)
如果我将代码更改为
println!("hello1");
tokio::spawn(async {set_timeout(|| println!("hello2"), 0)}.await).await;
println!("hello3");
tokio::spawn(async {set_timeout(|| println!("hello4"), 0)}.await).await;
println!("hello5");
Run Code Online (Sandbox Code Playgroud)
输出是
hello1
hello2 …Run Code Online (Sandbox Code Playgroud) 根据当前运行环境获取 tokio 运行时句柄的惯用方法是什么?
Handle.try_current().unwrap()它来获取当前的方法。Runtime::new().unwrap().handle()。但是,当我将代码编写为:
fn get_runtime_handle() -> Handle {
match Handle::try_current() {
Ok(h) => h,
Err(_) => Runtime::new().unwrap().handle().clone(),
}
}
async fn a_async() -> Result<()> {
....
}
fn a() -> Result<()> {
let handle = get_runtime_handle();
handle.block_one (async { a_async().await; })
}
fn main() -> Result<()> {
a();
Ok(())
}
Run Code Online (Sandbox Code Playgroud)
并tokio::fs::read_dir在内部调用,代码崩溃Error: Custom { kind: Other, error: "background task failed" }。
当我handle.block_on用Runtime::new().unwrap().handle().block_onin …
我想在 Rocket 服务器旁边启动 Tokio 事件循环,然后稍后将事件添加到该循环中。我读过有没有办法在新线程上启动 tokio::Delay 以允许主循环继续?,但我仍然不清楚如何实现我的目标。
Rust 中的 Future 可以在不阻塞的情况下进行轮询,以检查 future 是否准备好(并在此过程中做一些工作)。考虑到这一点,是否可以在不消耗其输出的情况下“检查”未来是否已准备好?
stdin如果有任何数据,将会被轮询,并对输入(playground)采取行动:
async fn read_input_if_available() {
use tokio::io::AsyncReadExt;
let mut stdin = tokio::io::stdin();
// if !stdin.ready() {
// return;
// }
let mut input = String::new();
let mut buffer = [0_u8; 1024];
while let Ok(bytes) = stdin.read(&mut buffer).await {
if let Ok(string) = std::str::from_utf8(&buffer[..bytes]) {
input.push_str(string);
}
}
// Take action on `input` here
}
Run Code Online (Sandbox Code Playgroud)
当代码命中 时await,直到标准输入上有内容为止,即使只是等待EOF.
我使用tokio::io::Stdin它是因为它对于一个独立的示例来说更简单,但问题是关于 Rust 期货的。
我无法理解如何编写封装在一个结构中的并发异步代码。
我不确定如何准确解释这个问题,所以我会尝试用一个例子来解释。
假设我有一个UdpServer结构。该结构有多个与其行为相关的方法(例如handle_datagram,,,deserialize_datagram等)
如果我想让代码并发,我将生成 tokio 任务,这需要提供给它的闭包是静态的,这意味着我无法&self从内部调用这个任务只要&self不是静态的,这意味着我不能调用self.serialize_datagram().
我理解这个问题(不能保证结构会比线程寿命更长),但看不到解决它的正确方法。我知道可以将函数移出 impl,但这对我来说看起来不是一个好的解决方案。
另外,即使我们暂时假设我可以将其视为&self静态,但出于某种原因,这段代码在我看来仍然不正确(我猜不够生锈)。
另一个“解决方案”是采取self: Arc<Self>而不是&self,但这感觉更糟。
所以我假设有一些我不知道的模式。有人可以向我解释一下我应该如何重构整个事情吗?
示例代码:
struct UdpServer {}
impl UdpServer {
pub async fn run(&self) {
let socket = UdpSocket::bind(self.addr).await.unwrap();
loop {
let mut buf: &mut [u8] = &mut [];
let (_, _) = socket.recv_from(&mut buf).await.unwrap();
// I spawn tokio task to enable concurrency
tokio::spawn(async move {
// But i can't use …Run Code Online (Sandbox Code Playgroud) 我正在尝试使用getrust 向 url 发出请求,每次运行此项目时都会收到此错误,而我的其他 rust 项目工作正常。这是我的cargo.toml文件。
[package]
name = "api_req"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
serde = { version = "1.0", features = ["derive"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1", features = ["full"]}
Run Code Online (Sandbox Code Playgroud)
这是我尝试构建/运行代码时得到的输出。
error: linking with `x86_64-w64-mingw32-gcc` failed: exit code: 1
|
= note: "x86_64-w64-mingw32-gcc" "-fno-use-linker-plugin" "-Wl,--dynamicbase" "-Wl,--disable-auto-image-base" "-m64" "-Wl,--high-entropy-va" "C:\\Users\\sahil\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\self-contained\\crt2.o" "C:\\Users\\sahil\\.rustup\\toolchains\\stable-x86_64-pc-windows-gnu\\lib\\rustlib\\x86_64-pc-windows-gnu\\lib\\rsbegin.o" "C:\\Users\\sahil\\CLionProjects\\coc-rs\\target\\debug\\deps\\coc_rs-6b97e9afad26cc80.1ax3t6bk8kjti15h.rcgu.o" …Run Code Online (Sandbox Code Playgroud) 我使用 tokio 实现了 TCP 客户端。但是,我的代码无法编译,因为出现错误:
error: future cannot be sent between threads safely
--> src/main.rs:81:9
|
81 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: within `impl Future<Output = ()>`, the trait `Send` is not implemented for `std::sync::MutexGuard<'_, Option<tokio::net::TcpStream>>`
note: future is not `Send` as this value is used across an await
--> src/main.rs:90:42
|
82 | match stream.lock().unwrap().as_mut() {
| ---------------------- has type `std::sync::MutexGuard<'_, Option<tokio::net::TcpStream>>` which is not `Send`
... …Run Code Online (Sandbox Code Playgroud)