#rust #timeout #tokio
Вопрос:
Я пытаюсь реализовать базовый алгоритм итеративного углубления в Rust:
pub async fn iterative_best_move(pos: amp;mut Position, col: PieceColour, timeout: u64) -> (Option<movegen::Move>, i32) {
let mut ret = (None, -1);
let mut time_remaining = std::time::Duration::from_secs(timeout);
let mut current_depth = 3;
loop {
let start = time::Instant::now();
let mut pos = pos.shallow_clone();
let x = tokio::time::timeout(time_remaining, async move {
depth_best_move(amp;mut pos, col, current_depth).await
}).await;
if let Err(_) = x {
// We ran out of time!
println!("Time's up!");
break;
}
ret = x.unwrap().unwrap();
time_remaining -= start.elapsed();
current_depth = 1;
}
println!("Depth {} in {} seconds.", current_depth, timeout);
ret
}
Проблема с моей реализацией заключается в том, что она, похоже, никогда не истекает по времени, вместо этого переходя к следующей итерации цикла и вызывая панику, когда она пытается представить отрицательную продолжительность.
Функция вызывается из main примерно так:
#[tokio::main]
async fn main() {
let mut pos = Position::random_legal();
let start = time::Instant::now();
search::iterative_best_move(amp;mut pos, piece::PieceColour::White, 5).await;
}
Почему функция не выполняет тайм-аут и не возвращается, как следовало бы?
Комментарии:
1. Я не думаю, что продолжительность может быть отрицательной, не могли бы вы добавить какой-нибудь журнал выполнения?
2. @Netwave Продолжительность действительно не может быть отрицательной. Однако это не должно иметь значения, так как условие if приведет к тому, что программа выйдет из цикла до того, как будет вычтено значение time_remaining.
3. да, но тогда что ты имеешь в виду? Произойдет ли это с ошибкой паники, если вместо этого вы используете фиксированный тайм-аут 0?
4. Во — первых, почему вы используете
async
для этой проблемы ? Во — вторых, нет никакой гарантии, что ваше будущее возобновится сразу же после.await
точки. Возможно, что в данный момент среда выполнения работает в другом будущем, и вам придется подождать. Таким образомstart.elapsed()
, необязательно отражать фактическое время, проведенное вdepth_best_move()
. ТАК что вы должны использовать doc.rust-lang.org/std/time/… во избежание незаполнения5. @DallasHewitt Это не так
tokio::time::timeout
работает. В общем, фьючерсы работают только тогда, когда они опрошены, таким образомtimeout
, опрашивается будущее, и если оно завершено, то оно возвращает результат, в противном случае оно опрашивает таймер и решает, отбросит ли оно будущее или нет. Но если будущее будет сложным с точки зрения вычислений, то опрос будет заблокирован на долгое время, поэтому тайм-аут никогда не сработает, это может занять больше времени, чем настроено для значения тайм-аута. Асинхронность/ожидание-это совместная модель, а не упреждающая