XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet
公开
关注 0 Fork 0 Star 1
返回提交历史

XFEstudio/gpt4free

perf(network): implement reusable connection pools with keep-alive and DNS caching

ede3339c
Anand Mall <anand@example.com>
提交于

代码差异

3 个文件 +47 -3
Modified g4f/providers/base_provider.py +2 -2
@@ -20,7 +20,7 @@ from .types import BaseProvider
20 20 from .asyncio import to_sync_generator, to_async_iterator
21 21 from .response import BaseConversation, AuthResult
22 22 from ..cookies import get_cookies_dir
23 from ..requests import raise_for_status
23 from ..requests import raise_for_status, StreamSession
24 24 from ..errors import (
25 25 ResponseError,
26 26 MissingAuthError,
@@ -337,7 +337,7 @@ class AsyncGeneratorProvider(AbstractProvider):
337 337 if not api_key and cls.needs_auth:
338 338 raise MissingAuthError("API key is required.")
339 339 headers = {"authorization": f"Bearer {api_key}"} if api_key else {}
340 async with ClientSession() as session:
340 async with StreamSession() as session:
341 341 async with session.get(cls.quota_url, headers=headers) as response:
342 342 await raise_for_status(response)
343 343 return await response.json()
Modified g4f/requests/__init__.py +1 -0
@@ -59,6 +59,7 @@ from ..errors import MissingRequirementsError
59 59 from ..typing import Cookies
60 60 from ..cookies import BrowserConfig, get_cookies_dir
61 61 from .defaults import DEFAULT_HEADERS, WEBVIEW_HAEDERS
62 from .aiohttp import get_shared_connector, close_shared_connectors
62 63
63 64 if not has_curl_cffi:
64 65
Modified g4f/requests/aiohttp.py +44 -1
@@ -1,11 +1,14 @@
1 1 from __future__ import annotations
2 2
3 3 import json
4 import asyncio
5 import weakref
4 6 from aiohttp import (
5 7 ClientSession,
6 8 ClientResponse,
7 9 ClientTimeout,
8 10 BaseConnector,
11 TCPConnector,
9 12 FormData,
10 13 )
11 14 from typing import AsyncIterator, Any, Optional
@@ -13,6 +16,35 @@ from typing import AsyncIterator, Any, Optional
13 16 from .defaults import DEFAULT_HEADERS, has_brotli
14 17 from ..errors import MissingRequirementsError
15 18
19 _loop_connectors: weakref.WeakKeyDictionary[asyncio.AbstractEventLoop, TCPConnector] = weakref.WeakKeyDictionary()
20
21
22 def get_shared_connector() -> Optional[TCPConnector]:
23 """Retrieve or create a loop-bound TCPConnector with keep-alive and DNS caching."""
24 try:
25 loop = asyncio.get_running_loop()
26 except RuntimeError:
27 return None
28 connector = _loop_connectors.get(loop)
29 if connector is None or connector.closed:
30 connector = TCPConnector(
31 limit=100,
32 limit_per_host=20,
33 keepalive_timeout=30,
34 ttl_dns_cache=300,
35 enable_cleanup_closed=True,
36 )
37 _loop_connectors[loop] = connector
38 return connector
39
40
41 async def close_shared_connectors() -> None:
42 """Close all open shared connectors."""
43 for connector in list(_loop_connectors.values()):
44 if not connector.closed:
45 await connector.close()
46 _loop_connectors.clear()
47
16 48
17 49 class StreamResponse(ClientResponse):
18 50 async def iter_lines(self) -> AsyncIterator[bytes]:
@@ -48,6 +80,7 @@ class StreamSession:
48 80 proxy: str = None,
49 81 proxies=None,
50 82 impersonate=None,
83 connector_owner: bool = None,
51 84 **kwargs,
52 85 ):
53 86 if proxies is None:
@@ -65,11 +98,21 @@ class StreamSession:
65 98 timeout = ClientTimeout(timeout, connect)
66 99 if proxy is None:
67 100 proxy = proxies.get("all", proxies.get("https"))
101
102 actual_connector = get_connector(connector, proxy)
103 if actual_connector is None and not proxy:
104 actual_connector = get_shared_connector()
105 if connector_owner is None and actual_connector is not None:
106 connector_owner = False
107 if connector_owner is None:
108 connector_owner = True
109
68 110 self.inner = ClientSession(
69 111 **kwargs,
70 112 timeout=timeout,
71 113 response_class=StreamResponse,
72 connector=get_connector(connector, proxy),
114 connector=actual_connector,
115 connector_owner=connector_owner,
73 116 headers=headers,
74 117 )
75 118