Rust tokio无限循环用于多按钮监听
我是个新手,我正在努力理解如何使用Rust tokio无限循环用于多按钮监听,rust,rust-tokio,Rust,Rust Tokio,我是个新手,我正在努力理解如何使用tokio在无限循环中阻塞代码。我有两个按钮连接到我的树莓皮3,我想听到任何一个按钮被按下。我用的是rust\gpiozero板条箱 以下是按钮代码: 使用RUSTgpiozero::*; 让mut按钮=按钮::新(19); 按钮。等待按(无);//在这里阻塞 我不知道如何连续地监听主代码中的任何一个按钮。我想我应该使用tokio::task::spawn_blocking,但我不确定如何使用。大概是这样的: #[tokio::main] 异步fn main(
tokio
在无限循环中阻塞代码。我有两个按钮连接到我的树莓皮3,我想听到任何一个按钮被按下。我用的是rust\gpiozero
板条箱
以下是按钮代码:
使用RUSTgpiozero::*;
让mut按钮=按钮::新(19);
按钮。等待按(无);//在这里阻塞
我不知道如何连续地监听主代码中的任何一个按钮。我想我应该使用tokio::task::spawn_blocking
,但我不确定如何使用。大概是这样的:
#[tokio::main]
异步fn main(){
让b1_blocking_task=tokio::task::spawn_blocking(| |){
让mut按钮=按钮::新(19);
按钮。等待按(无);//在此处阻塞
});
让b2_blocking_task=tokio::task::spawn_blocking(| |){
让mut按钮=按钮::新(26);
按钮。等待按(无);//在此处阻塞
});
循环{//永远听按钮按下
东京:选择{
_=b1_阻塞_任务=>{
println!(“按下按钮1”)
}
_=b2_阻塞_任务=>{
println!(“按下按钮2”)
}
};
}
}
上面的代码不起作用,但如何正确执行此操作的最佳策略是什么?对代码进行一点小改动即可使其正常工作:
#[tokio::main]
async fn main() {
let b1_blocking_task = || {
tokio::task::spawn_blocking(|| {
let mut button = Button::new(19);
button.wait_for_press(None); // blocks here
})
};
let b2_blocking_task = || {
tokio::task::spawn_blocking(|| {
let mut button = Button::new(26);
button.wait_for_press(None); // blocks here
})
};
loop {
// forever listen for button presses
tokio::select! {
_ = b1_blocking_task() => {
println!("Button 1 pressed")
}
_ = b2_blocking_task() => {
println!("Button 2 pressed")
}
};
}
}
这将为每次按下按钮产生一个新线程。这不是特别有效,但如果这些都是用户输入事件,可能也不太重要
只需生成每个线程一次,并使用通道在它们之间进行通信,就可以使其变得更好:
use tokio::sync::mpsc::channel;
#[tokio::main]
async fn main() {
// pick suitable queue sizes for these channels
let (mut b1_sender, mut b1_receiver) = channel(16);
let (mut b2_sender, mut b2_receiver) = channel(16);
let b1_blocking_task = tokio::task::spawn_blocking(|| {
let mut button = Button::new(19);
button.wait_for_press(None); // blocks here
// will panic if the channel queue gets full
b1_sender.try_send(()).unwrap();
});
let b2_blocking_task = tokio::task::spawn_blocking(|| {
let mut button = Button::new(26);
button.wait_for_press(None); // blocks here
// will panic if the channel queue gets full
b2_sender.try_send(()).unwrap();
});
let (_, _, _) = tokio::join!(
b1_blocking_task,
b2_blocking_task,
tokio::task::spawn(async move {
loop {
// forever listen for button presses
tokio::select! {
Some(_) = b1_receiver.recv() => {
println!("Button 1 pressed")
}
Some(_) = b2_receiver.recv() => {
println!("Button 2 pressed")
}
else => break
};
}
})
);
}
您使用的API并不理想,因为它要求您创建阻塞线程。如果有一种方法来轮询按钮以查看是否被单击,那会更好。在内部,板条箱似乎正在这样做,因此它应该可以公开该机制,这将让您在这方面进一步改进。对您的代码进行一个小的更改将使其工作:
#[tokio::main]
async fn main() {
let b1_blocking_task = || {
tokio::task::spawn_blocking(|| {
let mut button = Button::new(19);
button.wait_for_press(None); // blocks here
})
};
let b2_blocking_task = || {
tokio::task::spawn_blocking(|| {
let mut button = Button::new(26);
button.wait_for_press(None); // blocks here
})
};
loop {
// forever listen for button presses
tokio::select! {
_ = b1_blocking_task() => {
println!("Button 1 pressed")
}
_ = b2_blocking_task() => {
println!("Button 2 pressed")
}
};
}
}
这将为每次按下按钮产生一个新线程。这不是特别有效,但如果这些都是用户输入事件,可能也不太重要
只需生成每个线程一次,并使用通道在它们之间进行通信,就可以使其变得更好:
use tokio::sync::mpsc::channel;
#[tokio::main]
async fn main() {
// pick suitable queue sizes for these channels
let (mut b1_sender, mut b1_receiver) = channel(16);
let (mut b2_sender, mut b2_receiver) = channel(16);
let b1_blocking_task = tokio::task::spawn_blocking(|| {
let mut button = Button::new(19);
button.wait_for_press(None); // blocks here
// will panic if the channel queue gets full
b1_sender.try_send(()).unwrap();
});
let b2_blocking_task = tokio::task::spawn_blocking(|| {
let mut button = Button::new(26);
button.wait_for_press(None); // blocks here
// will panic if the channel queue gets full
b2_sender.try_send(()).unwrap();
});
let (_, _, _) = tokio::join!(
b1_blocking_task,
b2_blocking_task,
tokio::task::spawn(async move {
loop {
// forever listen for button presses
tokio::select! {
Some(_) = b1_receiver.recv() => {
println!("Button 1 pressed")
}
Some(_) = b2_receiver.recv() => {
println!("Button 2 pressed")
}
else => break
};
}
})
);
}
您使用的API并不理想,因为它要求您创建阻塞线程。如果有一种方法来轮询按钮以查看是否被单击,那会更好。在内部,板条箱似乎正在这样做,因此它应该有可能暴露该机制,这将让您在这方面进一步改进。在您衍生的任务中使用通道和循环。您好,星门,感谢您的响应。我不确定我是否明白,你的意思是把每个
wait\u for\u press
函数放在它自己的循环{}中,之后有一个通道发送调用?在生成的任务中使用一个通道和循环。您好,Stargateur,感谢您的响应。我不确定我是否遵循,你的意思是将每个wait\u for\u press
函数放在自己的循环{}中,之后使用一个频道发送调用?谢谢Peter,我怀疑板条箱的设计有点奇怪,但不确定,因为我缺乏生锈方面的经验。我会找更好的。仅供参考,由于按钮多次初始化,代码恐慌,说PinNotAvailable(19)
,但该策略似乎有效。第二段代码连续打印按钮1按下和按钮2按下
(我不按任何一个按钮)当我在我的PI3.0线程上运行它时,可能会出现恐慌,所以未来已经准备好了,并且报告没有。我不确定使用try_send是否有意义。谢谢Peter,我怀疑板条箱的设计有点奇怪,但不确定,因为我缺乏生锈方面的经验。我会找更好的。仅供参考,由于按钮多次初始化,代码恐慌,说PinNotAvailable(19)
,但该策略似乎有效。第二段代码连续打印按钮1按下和按钮2按下
(我不按任何一个按钮)当我在我的PI3.0线程上运行它时,可能会出现恐慌,所以未来已经准备好了,并且报告没有。我不确定使用try\u send是否有意义。