From a95a38078be80360099451c6c258e15b46e08d52 Mon Sep 17 00:00:00 2001 From: Zhi Yiliu <2584074296@qq.com> Date: Tue, 25 Nov 2025 01:20:00 +0800 Subject: [PATCH] [Fix] Fix uvloop get_event_loop() is not suitable for 0.22.x (#13612) Signed-off-by: lzy Co-authored-by: lzy --- benchmark/prefill_only/util.py | 14 +++++++------- python/pyproject.toml | 2 +- python/sglang/srt/entrypoints/engine.py | 3 +-- python/sglang/srt/grpc/grpc_request_manager.py | 4 ++-- python/sglang/srt/managers/tokenizer_manager.py | 8 +++++--- python/sglang/srt/multimodal/processors/llava.py | 2 +- python/sglang/srt/utils/common.py | 10 ++++++++++ python/sglang/test/few_shot_gsm8k_engine.py | 3 ++- test/srt/openai_server/basic/test_serving_chat.py | 6 +++--- 9 files changed, 32 insertions(+), 20 deletions(-) diff --git a/benchmark/prefill_only/util.py b/benchmark/prefill_only/util.py index 0dbc39027..3b3855916 100644 --- a/benchmark/prefill_only/util.py +++ b/benchmark/prefill_only/util.py @@ -240,7 +240,7 @@ async def make_http_call( api_name: Name of the API for error messages """ try: - start_time = asyncio.get_event_loop().time() + start_time = asyncio.get_running_loop().time() request_json = build_http_request_json(request_data) headers = {"Content-Type": "application/json"} @@ -253,7 +253,7 @@ async def make_http_call( f"[HTTP] {api_name} Request {request_id} failed with status " f"{resp.status}: {resp_text}" ) - completion_time = asyncio.get_event_loop().time() + completion_time = asyncio.get_running_loop().time() await results_queue.put((request_id, 0, False, completion_time)) return @@ -271,13 +271,13 @@ async def make_http_call( ) success = False - completion_time = asyncio.get_event_loop().time() + completion_time = asyncio.get_running_loop().time() elapsed_time = (completion_time - start_time) * 1000 await results_queue.put((request_id, elapsed_time, success, completion_time)) except Exception as e: print(f"[HTTP] {api_name} Error for request {request_id}: {e}") - completion_time = asyncio.get_event_loop().time() + completion_time = asyncio.get_running_loop().time() await results_queue.put((request_id, 0, False, completion_time)) @@ -738,7 +738,7 @@ async def run_generic_benchmark( tasks = [] # Track timing for sending requests - send_start_time = asyncio.get_event_loop().time() + send_start_time = asyncio.get_running_loop().time() # HTTP implementation async with aiohttp.ClientSession( @@ -778,7 +778,7 @@ async def run_generic_benchmark( if i < len(all_requests) - 1: await sleep_with_distribution(config.distribution, rps) - send_end_time = asyncio.get_event_loop().time() + send_end_time = asyncio.get_running_loop().time() send_duration = send_end_time - send_start_time # Wait for all requests to complete with progress tracking @@ -796,7 +796,7 @@ async def run_generic_benchmark( if config.profile: await send_profile_request("STOP_PROFILE", http_url, session=session) - completion_end_time = asyncio.get_event_loop().time() + completion_end_time = asyncio.get_running_loop().time() total_duration = completion_end_time - send_start_time return await process_results( diff --git a/python/pyproject.toml b/python/pyproject.toml index 836bf572c..0e89aec49 100755 --- a/python/pyproject.toml +++ b/python/pyproject.toml @@ -69,7 +69,7 @@ dependencies = [ "tqdm", "transformers==4.57.1", "uvicorn", - "uvloop==0.21.0", + "uvloop", "xgrammar==0.1.27", "grpcio==1.75.1", # keep it align with compile_proto.py "grpcio-tools==1.75.1", # keep it align with compile_proto.py diff --git a/python/sglang/srt/entrypoints/engine.py b/python/sglang/srt/entrypoints/engine.py index 19c4e29a7..96070b954 100644 --- a/python/sglang/srt/entrypoints/engine.py +++ b/python/sglang/srt/entrypoints/engine.py @@ -533,8 +533,7 @@ class Engine(EngineBase): zmq_handles=zmq_handles, flush_cache=flush_cache, ) - loop = asyncio.get_event_loop() - return loop.run_until_complete( + return self.loop.run_until_complete( self.tokenizer_manager.update_weights_from_ipc(obj, None) ) diff --git a/python/sglang/srt/grpc/grpc_request_manager.py b/python/sglang/srt/grpc/grpc_request_manager.py index 228ab55cb..fb79f4ff1 100644 --- a/python/sglang/srt/grpc/grpc_request_manager.py +++ b/python/sglang/srt/grpc/grpc_request_manager.py @@ -28,7 +28,7 @@ from sglang.srt.managers.io_struct import ( TokenizedGenerateReqInput, ) from sglang.srt.server_args import PortArgs, ServerArgs -from sglang.srt.utils import get_zmq_socket, kill_process_tree +from sglang.srt.utils import get_or_create_event_loop, get_zmq_socket, kill_process_tree from sglang.utils import get_exception_traceback logger = logging.getLogger(__name__) @@ -876,7 +876,7 @@ class GrpcRequestManager: return self.no_create_loop = True - loop = asyncio.get_event_loop() + loop = get_or_create_event_loop() self.asyncio_tasks.add( loop.create_task(print_exception_wrapper(self.handle_loop)) ) diff --git a/python/sglang/srt/managers/tokenizer_manager.py b/python/sglang/srt/managers/tokenizer_manager.py index 7e303d8b0..59694c30b 100644 --- a/python/sglang/srt/managers/tokenizer_manager.py +++ b/python/sglang/srt/managers/tokenizer_manager.py @@ -98,6 +98,7 @@ from sglang.srt.utils import ( dataclass_to_string_truncated, freeze_gc, get_bool_env_var, + get_or_create_event_loop, get_zmq_socket, kill_process_tree, ) @@ -1354,12 +1355,13 @@ class TokenizerManager(TokenizerCommunicatorMixin): def auto_create_handle_loop(self): if self._chosen_loop is not None: + current_loop = get_or_create_event_loop() assert ( - asyncio.get_event_loop() == self._chosen_loop - ), f"Please ensure only one event loop is ever used with SGLang. Previous loop: {self._chosen_loop}, current loop: {asyncio.get_event_loop()}" + current_loop == self._chosen_loop + ), f"Please ensure only one event loop is ever used with SGLang. Previous loop: {self._chosen_loop}, current loop: {current_loop}" return - loop = asyncio.get_event_loop() + loop = get_or_create_event_loop() self._chosen_loop = loop self.asyncio_tasks.add( loop.create_task(print_exception_wrapper(self.handle_loop)) diff --git a/python/sglang/srt/multimodal/processors/llava.py b/python/sglang/srt/multimodal/processors/llava.py index 1647ea1e5..98f5b7970 100644 --- a/python/sglang/srt/multimodal/processors/llava.py +++ b/python/sglang/srt/multimodal/processors/llava.py @@ -89,7 +89,7 @@ class LlavaImageProcessor(BaseMultimodalProcessor): grid_pinpoints: str, ): if self.cpu_executor is not None: - loop = asyncio.get_event_loop() + loop = asyncio.get_running_loop() return await loop.run_in_executor( self.cpu_executor, LlavaImageProcessor._process_single_image_task, diff --git a/python/sglang/srt/utils/common.py b/python/sglang/srt/utils/common.py index e1d2accbb..a7e25799b 100644 --- a/python/sglang/srt/utils/common.py +++ b/python/sglang/srt/utils/common.py @@ -104,6 +104,16 @@ show_time_cost = False time_infos = {} +def get_or_create_event_loop(): + """Gets the running event loop or creates a new one if it doesn't exist.""" + try: + return asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop + + HIP_FP8_E4M3_FNUZ_MAX = 224.0 diff --git a/python/sglang/test/few_shot_gsm8k_engine.py b/python/sglang/test/few_shot_gsm8k_engine.py index 07eda86e2..13a30be1c 100644 --- a/python/sglang/test/few_shot_gsm8k_engine.py +++ b/python/sglang/test/few_shot_gsm8k_engine.py @@ -8,6 +8,7 @@ from typing import Optional import numpy as np import sglang as sgl +from sglang.srt.utils import get_or_create_event_loop from sglang.utils import download_and_cache_file, read_jsonl INVALID = -9999999 @@ -89,7 +90,7 @@ def run_eval(args): # Run requests tic = time.perf_counter() - loop = asyncio.get_event_loop() + loop = get_or_create_event_loop() outputs = loop.run_until_complete( concurrent_generate(engine, prompts, sampling_param) diff --git a/test/srt/openai_server/basic/test_serving_chat.py b/test/srt/openai_server/basic/test_serving_chat.py index fbbbcccdd..b4f44041f 100644 --- a/test/srt/openai_server/basic/test_serving_chat.py +++ b/test/srt/openai_server/basic/test_serving_chat.py @@ -6,7 +6,6 @@ or python -m unittest discover -s tests -p "test_*unit.py" -v """ -import asyncio import json import unittest import uuid @@ -21,6 +20,7 @@ from sglang.srt.entrypoints.openai.protocol import ( ) from sglang.srt.entrypoints.openai.serving_chat import OpenAIServingChat from sglang.srt.managers.io_struct import GenerateReqInput +from sglang.srt.utils import get_or_create_event_loop class _MockTokenizerManager: @@ -389,7 +389,7 @@ class ServingChatTestCase(unittest.TestCase): break return line - loop = asyncio.get_event_loop() + loop = get_or_create_event_loop() line = loop.run_until_complete(collect_first_tool_chunk()) self.assertIsNotNone(line) self.assertTrue(line.startswith("data: ")) @@ -564,7 +564,7 @@ class ServingChatTestCase(unittest.TestCase): break return line - loop = asyncio.get_event_loop() + loop = get_or_create_event_loop() line = loop.run_until_complete(collect_first_tool_chunk()) self.assertIsNotNone(line) self.assertTrue(line.startswith("data: "))