perf(selection): 优化选股执行性能
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
"""HTTP presentation for persisted strategy execution results."""
|
||||
|
||||
import atexit
|
||||
import threading
|
||||
from datetime import date, datetime
|
||||
from typing import Annotated, Literal
|
||||
|
||||
@@ -17,6 +19,7 @@ from zhixing_server.modules.selection.domain.runs import (
|
||||
SelectionRunInProgress,
|
||||
SelectionRunStoreError,
|
||||
)
|
||||
from zhixing_server.modules.selection.infrastructure.postgres_pool import SelectionPostgresPool
|
||||
from zhixing_server.modules.selection.infrastructure.postgres_reader import (
|
||||
PostgresMarketDataReader,
|
||||
SelectionMarketDataNotReady,
|
||||
@@ -27,6 +30,8 @@ from zhixing_server.modules.selection.infrastructure.postgres_runs import (
|
||||
)
|
||||
|
||||
selection_router = APIRouter()
|
||||
_SELECTION_POOL_CACHE_LOCK = threading.Lock()
|
||||
_SELECTION_POOL_CACHE: dict[tuple[str, int], SelectionPostgresPool] = {}
|
||||
|
||||
StrategyValue = Literal["zhixing_b1"]
|
||||
SelectionStatusValue = Literal[
|
||||
@@ -117,11 +122,45 @@ class SelectionResultsResponse(BaseModel):
|
||||
def get_selection_service(
|
||||
settings: Annotated[Settings, Depends(get_settings)],
|
||||
) -> RunZhixingB1:
|
||||
"""Build one request-scoped selection application service."""
|
||||
"""Build the selection service on top of process-scoped shared resources."""
|
||||
|
||||
reader = PostgresMarketDataReader(settings)
|
||||
store = PostgresSelectionRunRepository(settings.database_url)
|
||||
return RunZhixingB1(reader, store)
|
||||
pool = get_selection_postgres_pool(settings)
|
||||
reader = PostgresMarketDataReader(settings, pool=pool)
|
||||
store = PostgresSelectionRunRepository(settings.database_url, pool=pool)
|
||||
return RunZhixingB1(
|
||||
reader,
|
||||
store,
|
||||
max_workers=settings.selection_max_workers,
|
||||
batch_size=settings.selection_batch_size,
|
||||
)
|
||||
|
||||
|
||||
def get_selection_postgres_pool(settings: Settings) -> SelectionPostgresPool:
|
||||
"""Return the cached bounded pool shared by selection adapters."""
|
||||
|
||||
key = (settings.database_url, settings.selection_max_workers + 2)
|
||||
with _SELECTION_POOL_CACHE_LOCK:
|
||||
pool = _SELECTION_POOL_CACHE.get(key)
|
||||
if pool is None:
|
||||
pool = SelectionPostgresPool(
|
||||
settings.database_url,
|
||||
max_connections=key[1],
|
||||
)
|
||||
_SELECTION_POOL_CACHE[key] = pool
|
||||
return pool
|
||||
|
||||
|
||||
def _close_cached_selection_pools() -> None:
|
||||
"""Close all process-cached selection pools during interpreter shutdown."""
|
||||
|
||||
with _SELECTION_POOL_CACHE_LOCK:
|
||||
pools = tuple(_SELECTION_POOL_CACHE.values())
|
||||
_SELECTION_POOL_CACHE.clear()
|
||||
for pool in pools:
|
||||
pool.close()
|
||||
|
||||
|
||||
atexit.register(_close_cached_selection_pools)
|
||||
|
||||
|
||||
@selection_router.post(
|
||||
@@ -292,5 +331,6 @@ __all__ = [
|
||||
"SelectionRunAcceptedResponse",
|
||||
"SelectionRunRequest",
|
||||
"get_selection_service",
|
||||
"get_selection_postgres_pool",
|
||||
"selection_router",
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user