Size: a a a

2021 July 12

m

mAX in Rust Async
Товарищи, подскажите пожалуйста
Есть асинхронный код сервер, но в один поток (через tokio::task::LocalSet и tokio::task::spawn_local)
Все работает вроде бы нормально, но иногда цикл обработки сообщений блочится намертво на несколько секунд.. при этом от сервера отваливаются соединения по таймауту, т.к. на Ping websocket сервер уже не имел возможности ответить. Клиенты получив таймаут реконнектятся и когда сервер отвисает сразу много новых подключений в течении 1-2мс

Есть ли какие-нибудь удобные инструменты чтобы отловить блокирующий участок?
В подобном случае же получается что один из вызовов poll какой-то фьючи был очень длинным и подвесил поток, можно ли как-то автоматически задетектить какой участок кода к этому привел?
источник

DF

Dollar Føølish in Rust Async
Есть offcpu профилировщики, можно bcc заюзать, а можно и перф наколхозить скрипт
источник

DF

Dollar Føølish in Rust Async
Ну или когда оно там висит дебаггером подцепись
источник

KK

Kirill (Cykooz) Kuzm... in Rust Async
А по коду разве не видно блокирующие вызовы? Ищи разного рода циклы, внутри которых нет await. Или где идёт синхронная работа с файлами или вызов других синхронных функций.
Вроде как одним из плюсов асинхронки, по сравнению с другими моделями конкурентности, является как раз явность тех мест в коде, где может происходить переключение контекста (и где оно не может быть).
источник

KK

Kirill (Cykooz) Kuzm... in Rust Async
Может в токио есть какие-то дебаг-логи, которые покажут на чём именно у тебя случаются подвисания, какие "корутины" выполняются долго без возврата управления евент лупу.
источник

m

mAX in Rust Async
Как бы все старалось быть асинхронным, поэтому и спрашивал в вопрсе о каких-то автоматических тулзах и средствах диагностики..
Единственное RwLock там parking_lot.. но вроде бы он никогда не должен блочить надолго
источник

KK

Kirill (Cykooz) Kuzm... in Rust Async
Я бы предположил, что самое простое и эффективное решение должно быть внутри евент-лупа - лог с временем, затраченным на один "шаг" обработки корутины.
источник

m

mAX in Rust Async
ну вот да, что-то такое в токио
чтобы можно было режим какой-то включить и пусть оно измеряет и длительность переходов между .await в разных кусках считает, например
источник

DO

Denis Otkydach in Rust Async
Во время удержания лока нет await-ов? Из доки:

As a rule of thumb, using a synchronous mutex from within asynchronous code is fine as long as contention remains low and the lock is not held across calls to .await.
источник

m

mAX in Rust Async
нет, там просто RwLock read() write()
причем там условно BTreeMap под локом и вроде бы не должно быть ничего такого что может его надолго подвесить

я старался всегда копировать переменные из под лока и потом использовать.. как-то так
let v = { v.read().v.clone() };
при записи аналогично..

попробую все на асинхронный лок перевести
источник

YM

Yaro M in Rust Async
Привет

Сами tokio предлагают использовать крейт tracing на своем сайте

Хорошо помогает linux-утилита strace увидеть какие системные вызовы происходят

И проверить не случается ли что-то в роде dead-lock на этом мутексе
источник

DF

Dollar Føølish in Rust Async
strace еще и мини-профайлер реализует немношк ага
источник

DF

Dollar Føølish in Rust Async
так что полезно было бы ей воспользоваться предварительно ознакомившись с фичами
источник

ph

pl 🦑 hk in Rust Async
источник

PL

Paul ❌ Loyd in Rust Async
Гварды в parking_lot по умолчанию (без фичи send_guard) не реализуют Send, так что компилятор не даст через await переехать с синхронным мьютекстом
источник

DF

Dollar Føølish in Rust Async
мм, а как работает фича send_guard?
источник

DF

Dollar Føølish in Rust Async
типа она что-то в гардах меняет или в самих мутексах?
источник

П

Пух in Rust Async
#[cfg(feature = "send_guard")]
type GuardMarker = lock_api::GuardSend;
#[cfg(not(feature = "send_guard"))]
type GuardMarker = lock_api::GuardNoSend;
источник

DF

Dollar Føølish in Rust Async
ага, значит гард другой используется спасибо
источник

П

Пух in Rust Async
/// Marker type which indicates that the Guard type for a lock is Send.
pub struct GuardSend(());

/// Marker type which indicates that the Guard type for a lock is not Send.
pub struct GuardNoSend(*mut ());

unsafe impl Sync for GuardNoSend {}
источник