Skip to content

llama.cpp backend: настоящий по-токенный стриминг, лок на контекст, отмена при обрыве клиента#1

Merged
Ferraronp merged 2 commits into
Ferraronp:mainfrom
zttoyk-create:fix/llamacpp-streaming-races
Jun 17, 2026

Conversation

@zttoyk-create

Copy link
Copy Markdown

Проблемы и фиксы

1. Стриминг был фиктивным (главное)

_llama_cpp_job заполнял tokens_list одним extend() после полного завершения генерации LLM — flow matching не мог начаться, пока LLM не догенерирует всё (TTFB = время всей генерации). Теперь токены пишутся ПО ОДНОМУ через on_token-колбэк в _run_llama_cpp_inference — LLM и flow реально перекрываются, первый аудио-чанк выходит после ~token_hop_len + pre_lookahead токенов.

2. Поллинг sleep(0.1)threading.Condition

tts_stream_external_llm просыпался раз в 100мс; теперь консьюмер будится notify_all() сразу по каждому токену. Заодно убрана гонка: done и available теперь читаются под одним локом (раньше «протухший» available из прошлой итерации мог досрочно уронить хвост в финальный чанк).

3. Общий llama.cpp контекст без лока

llm_gguf один на все запросы: параллельный reset() ломал KV-кеш живой генерации (битый звук/мусорные токены). Добавлен self._llama_lock, вся последовательность reset/eval/sample сериализована.

4. Осиротевший LLM-поток при обрыве клиента

Если клиент бросал стрим (GeneratorExit), llm_thread.join() после цикла не выполнялся — поток продолжал генерировать, а следующий запрос делал reset() параллельно с его eval(). Теперь: cancel_event (проверяется в цикле генерации) + try/finally с join(30) во всех 3 stream-ветках (zero_shot / cross_lingual / instruct2).

5. Утечка hift_cache

tts_with_external_tokens: исключение в token2wav оставляло запись в hift_cache_dict навсегда — pop перенесён в finally.

Совместимость

  • tokens_cond и cancel_event — опциональные параметры, старые вызовы работают без изменений (fallback на короткий поллинг).
  • PyTorch-путь (без llama.cpp) не тронут.

⚠️ Проверить на GPU

  • stream-режим: TTFB должен упасть с «вся генерация» до первых ~35-50 токенов
  • обрыв клиента посреди стрима → следующий запрос должен отработать чисто
  • несколько параллельных запросов → сериализуются без порчи звука

После проверки имеет смысл обновить PR FunAudioLLM#1872 в upstream. 🦊

… отмена и join в finally

- _llama_cpp_job пишет токены в tokens_list ПО ОДНОМУ через on_token-колбэк:
  раньше был один extend() ПОСЛЕ всей генерации — flow не мог начаться,
  пока LLM не закончит полностью (TTFB = вся генерация, стриминг фиктивный)
- threading.Condition вместо поллинга: консьюмер просыпается сразу по токену
- self._llama_lock: общий llama.cpp контекст не thread-safe, параллельный
  reset() ломал KV-кеш живой генерации
- cancel_event + try/finally join(30): при обрыве клиента (GeneratorExit)
  join после цикла не выполнялся — осиротевший поток продолжал генерацию
… pop в finally

- tts_stream_external_llm: принимает tokens_cond — консьюмер просыпается
  сразу по появлению токена (поллинг добавлял до 100мс на чанк);
  done и available читаются под одним локом — убрана гонка со «протухшим»
  available, из-за которой хвост мог уйти в финальный чанк раньше времени
- tts_with_external_tokens: pop hift_cache в finally — исключение в token2wav
  больше не оставляет вечную запись в hift_cache_dict (утечка памяти)
@Ferraronp Ferraronp merged commit e9bd821 into Ferraronp:main Jun 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants