목차
1. 간단하고 투박한 방법 - mysql 라이브러리를 캡슐화
2. Python 프로브
먼저 Cursor.execute의 소스 코드(cursor.executemanay도 유사)에서는 self.nextset의 메서드가 먼저 호출되어 이전 요청의 데이터를 가져온 다음 SQL 문을 병합하는 것으로 나타났습니다. 그리고 마지막으로 self._query를 통해 쿼리합니다.
반복되는 소개를 줄이는 원리는 모듈이 소개될 때마다 sys.modules에 저장된다는 것입니다. 반복적으로 도입되는 경우에는 가장 최근에 도입된 모듈로 바로 새로고침됩니다. 위에서 반복 가져오기를 줄이는 것을 고려하는 이유는 프로그램이 실행될 때 타사 라이브러리 종속성을 업그레이드하지 않기 때문입니다. 동일한 이름과 다른 구현을 가진 모듈을 반복적으로 도입하는 것을 고려할 필요가 없다는 점과 sys.modules가 가져온 모듈을 캐시한다는 점을 활용하여 위의 논리를 모듈 가져오기로 단순화할 수 있습니다. -> 현재 모듈 메서드를 다음으로 대체할 수 있습니다. 우리가 수정한 후크 방법.
백엔드 개발 파이썬 튜토리얼 Python 프로브는 호출 라이브러리에서 데이터 추출을 어떻게 완료합니까?

Python 프로브는 호출 라이브러리에서 데이터 추출을 어떻게 완료합니까?

May 16, 2023 am 08:46 AM
python

1. 간단하고 투박한 방법 - mysql 라이브러리를 캡슐화

실행 프로세스를 계산하려면 실행 프로세스의 시작 위치와 끝 위치를 알아야 하므로 가장 간단하고 투박한 방법은 해당 방법을 기반으로 캡슐화하는 것입니다. 라는, MySQL 라이브러리를 호출하는 프레임워크와 MySQL 라이브러리 사이에 중간 계층을 구현하고 중간 계층에서 시간이 많이 걸리는 통계를 완료합니다. 예:

# 伪代码
def my_execute(conn, sql, param):
 # 针对MySql库的统计封装组件
 with MyTracer(conn, sql, param):
     # 以下为正常使用MySql库的代码
with conn.cursor as cursor:
 cursor.execute(sql, param)
...
로그인 후 복사

구현하기가 매우 좋은 것 같습니다. 변경하기 편리하지만 최상위 API에 있기 때문에 수정하는 것은 실제로 매우 유연하지 않습니다. 동시에 sql 및 param 연결, nextset 호출과 같은 일부 사전 작업이cursor.execute에서 수행됩니다. 현재 커서 데이터 등 우리가 최종적으로 얻은 시간, 소비량 등의 데이터도 부정확했고 오류 코드 등 일부 세부적인 메타데이터를 얻을 방법이 없었습니다.

가장 직접적으로 유용한 데이터를 얻으려면 소스 코드를 변경한 다음 소스 코드를 호출하면 되지만 각 라이브러리에서 계산하기 위해 소스 코드를 변경해야 하는 경우에는 너무 번거로울 수 있습니다. 다행히도 Python은 프로브와 유사한 일부 인터페이스를 제공하며 라이브러리의 소스 코드는

2. Python 프로브

Python에서는 가져오기 관련 작업을 수행할 때 가져오기 관련 라이브러리를 구현할 수 있습니다. sys.meta_path에 정의된 개체를 기반으로 일치합니다. .sys.meta_path의 개체를 변경하려면 find_module 메서드를 구현해야 합니다. 이 find_module 메서드는 None 또는 load_module 메서드를 구현하는 개체를 반환합니다. 몇몇 라이브러리를 임포트할 때 관련 방법은 간단합니다. 자신만의 프로브 모듈을 만드는 경우, 예제는 aiomysql 모듈에만 관련되므로 MetaPathFinder.find_module에서 aiomysql 모듈만 처리하면 되고 나머지는 먼저 무시됩니다. 그런 다음 우리가 원하는 aiomysql의 기능을 결정해야 합니다. 비즈니스 관점에서 보면 일반적으로cursor.execute,cursor.fetchone,cursor.fetchall,cursor.executemany만 필요하므로 코드를 변경하는 방법과 어떤 기능을 수행하는지 확인하려면 커서에 대해 자세히 살펴봐야 합니다.

먼저 Cursor.execute의 소스 코드(cursor.executemanay도 유사)에서는 self.nextset의 메서드가 먼저 호출되어 이전 요청의 데이터를 가져온 다음 SQL 문을 병합하는 것으로 나타났습니다. 그리고 마지막으로 self._query를 통해 쿼리합니다.

import importlib
import sys
from functools import wraps
def func_wrapper(func):
    """这里通过一个装饰器来达到狸猫换太子和获取数据的效果"""
    @wraps(func)
    def wrapper(*args, **kwargs):
        # 记录开始时间
        start = time.time()
        result = func(*args, **kwargs)
        # 统计消耗时间
        end = time.time()
        print(f"speed time:{end - start}")
        return result
    return wrapper
class MetaPathFinder:
    def find_module(self, fullname, path=None):
        # 执行时可以看出来在import哪些模块
        print(f'find module:{path}:{fullname}')
        return MetaPathLoader()
class MetaPathLoader:
    def load_module(self, fullname):
        # import的模块都会存放在sys.modules里面, 通过判断可以减少重复import
        if fullname in sys.modules:
            return sys.modules[fullname]
        # 防止递归调用
        finder = sys.meta_path.pop(0)
        # 导入 module
        module = importlib.import_module(fullname)
        if fullname == 'time':
            # 替换函数
            module.sleep = func_wrapper(module.sleep)
        sys.meta_path.insert(0, finder)
        return module
sys.meta_path.insert(0, MetaPathFinder())
if __name__ == '__main__':
    import time
    time.sleep(1)
# 输出示例:
# find module:datetime
# find module:time
# load module:time
# find module:math
# find module:_datetime
# speed time:1.00073385238647468
로그인 후 복사

cursor.fetchone(cursor.fetchall도 유사)의 소스 코드를 보면 데이터가 실제로 캐시에서 얻은 것을 알 수 있습니다.

이 데이터는 동안 얻은 것입니다. Cursor.execute 실행:

async def execute(self, query, args=None):
    """Executes the given operation
    Executes the given operation substituting any markers with
    the given parameters.
    For example, getting all rows where id is 5:
        cursor.execute("SELECT * FROM t1 WHERE id = %s", (5,))
    :param query: ``str`` sql statement
    :param args: ``tuple`` or ``list`` of arguments for sql query
    :returns: ``int``, number of rows that has been produced of affected
    """
    conn = self._get_db()

    while (await self.nextset()):
        pass

    if args is not None:
        query = query % self._escape_args(args, conn)

    await self._query(query)
    self._executed = query
    if self._echo:
        logger.info(query)
        logger.info("%r", args)
    return self._rowcount
로그인 후 복사

위의 분석을 바탕으로 핵심 메서드 self._query만 오버로드하면 됩니다. 소스 코드에서 원하는 데이터를 얻을 수 있음을 알 수 있습니다. 그리고 self._query에 전달된 sql 매개변수를 사용하면 self를 기반으로 쿼리 결과를 얻을 수 있으며 동시에 데코레이터를 통해 실행 결과를 얻을 수 있습니다.

아이디어에 따라 수정된 코드는 다음과 같습니다.

def fetchone(self):
    """Fetch the next row """
    self._check_executed()
    fut = self._loop.create_future()
    if self._rows is None or self._rownumber >= len(self._rows):
        fut.set_result(None)
        return fut
    result = self._rows[self._rownumber]
    self._rownumber += 1
    fut = self._loop.create_future()
    fut.set_result(result)
    return fut
로그인 후 복사

이 예제는 매우 좋아 보이지만 호출 시작 시 로직을 명시적으로 호출해야 하며, 일반적으로 프로젝트의 경우 각 입구가 여러 개 있을 수 있습니다. 이 로직을 호출하는 것은 매우 번거롭고 가져오기 전에 먼저 후크 로직을 호출해야 함을 보여줍니다. 이런 식으로 도입 사양을 설정해야 합니다. 그렇지 않으면 후크가 일부 위치에서 성공하지 못할 수 있습니다. 파서가 시작된 후 즉시 실행되도록 후크를 도입하는 논리를 배열함으로써 완벽하게 해결되었습니다. 정보를 확인한 후 Python 인터프리터가 초기화되면 PYTHONPATH에 존재하는 sitecustomize 및 usercustomize 모듈을 자동으로 가져오는 것을 발견했습니다. 모듈을 생성하고 모듈에 대체 함수를 작성합니다.

import importlib
import time
import sys
from functools import wraps
from typing import cast, Any, Callable, Optional, Tuple, TYPE_CHECKING
from types import ModuleType
if TYPE_CHECKING:
    import aiomysql
def func_wrapper(func: Callable):
    @wraps(func)
    async def wrapper(*args, **kwargs) -> Any:
        start: float = time.time()
        func_result: Any = await func(*args, **kwargs)
        end: float = time.time()
        # 根据_query可以知道, 第一格参数是self, 第二个参数是sql
        self: aiomysql.Cursor = args[0]
        sql: str = args[1]
        # 通过self,我们可以拿到其他的数据
        db: str = self._connection.db
        user: str = self._connection.user
        host: str = self._connection.host
        port: str = self._connection.port
        execute_result: Tuple[Tuple] = self._rows
        # 可以根据自己定义的agent把数据发送到指定的平台, 然后我们就可以在平台上看到对应的数据或进行监控了, 
        # 这里只是打印一部分数据出来
        print({
            "sql": sql,
            "db": db,
            "user": user,
            "host": host,
            "port": port,
            "result": execute_result,
            "speed time": end - start
        })
        return func_result
    return cast(Callable, wrapper)
class MetaPathFinder:

    @staticmethod
    def find_module(fullname: str, path: Optional[str] = None) -> Optional["MetaPathLoader"]:
        if fullname == 'aiomysql':
            # 只有aiomysql才进行hook
            return MetaPathLoader()
        else:
            return None
class MetaPathLoader:
    @staticmethod
    def load_module(fullname: str):
        if fullname in sys.modules:
            return sys.modules[fullname]
        # 防止递归调用
        finder: "MetaPathFinder" = sys.meta_path.pop(0)
        # 导入 module
        module: ModuleType = importlib.import_module(fullname)
        # 针对_query进行hook
        module.Cursor._query = func_wrapper(module.Cursor._query)
        sys.meta_path.insert(0, finder)
        return module
async def test_mysql() -> None:
    import aiomysql
    pool: aiomysql.Pool = await aiomysql.create_pool(
        host='127.0.0.1', port=3306, user='root', password='123123', db='mysql'
    )
    async with pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute("SELECT 42;")
            (r,) = await cur.fetchone()
            assert r == 42
    pool.close()
    await pool.wait_closed()

if __name__ == '__main__':
    sys.meta_path.insert(0, MetaPathFinder())
    import asyncio
    asyncio.run(test_mysql())
# 输出示例:
# 可以看出sql语句与我们输入的一样, db, user, host, port等参数也是, 还能知道执行的结果和运行时间
# {'sql': 'SELECT 42;', 'db': 'mysql', 'user': 'root', 'host': '127.0.0.1', 'port': 3306, 'result': ((42,),), 'speed time': 0.00045609474182128906}
로그인 후 복사
hook_aiomysql.py는 프로브를 만들기 위한 코드이며 sitecustomize.py에 저장된 코드는 다음과 같습니다. 매우 간단합니다. 프로브 코드를 입력하고 sys.meta_path에 삽입하면 됩니다.

.
├── __init__.py
├── hook_aiomysql.py
├── sitecustomize.py
└── test_auto_hook.py
로그인 후 복사

test_auto_hook.py 테스트 코드는 다음과 같습니다.

import sys
from hook_aiomysql import MetaPathFinder
sys.meta_path.insert(0, MetaPathFinder())
로그인 후 복사

다음으로 PYTHONPATH를 설정하고 코드를 실행하기만 하면 됩니다(프로젝트인 경우 일반적으로 감독자가 시작하며 PYTHONPATH는 구성 파일에서 설정할 수 있습니다). :

import asyncio
from hook_aiomysql import test_mysql
asyncio.run(test_mysql())
로그인 후 복사
4. 직접 교체 방법

위의 방법이 매우 잘 실행되고 우리 프로젝트에 쉽게 삽입될 수 있음을 알 수 있습니다. 그러나 해당 방법에 따라 타사 라이브러리로 추출하기가 어렵습니다. sitecustomize.py 파일을 참조하세요. 타사 라이브러리를 분리하려면 다른 방법이 있는지 고려해야 합니다. 위에서 MetaPathLoader를 소개할 때 sys.modules를 언급했는데, 여기서는 반복되는 소개를 줄이기 위해 sys.modules를 사용합니다.

(.venv) ➜  python_hook git:(master) ✗ export PYTHONPATH=.      
(.venv) ➜  python_hook git:(master) ✗ python test_auto_hook.py 
{'sql': 'SELECT 42;', 'db': 'mysql', 'user': 'root', 'host': '127.0.0.1', 'port': 3306, 'result': ((42,),), 'speed time': 0.000213623046875}
로그인 후 복사

반복되는 소개를 줄이는 원리는 모듈이 소개될 때마다 sys.modules에 저장된다는 것입니다. 반복적으로 도입되는 경우에는 가장 최근에 도입된 모듈로 바로 새로고침됩니다. 위에서 반복 가져오기를 줄이는 것을 고려하는 이유는 프로그램이 실행될 때 타사 라이브러리 종속성을 업그레이드하지 않기 때문입니다. 동일한 이름과 다른 구현을 가진 모듈을 반복적으로 도입하는 것을 고려할 필요가 없다는 점과 sys.modules가 가져온 모듈을 캐시한다는 점을 활용하여 위의 논리를 모듈 가져오기로 단순화할 수 있습니다. -> 현재 모듈 메서드를 다음으로 대체할 수 있습니다. 우리가 수정한 후크 방법.

import time
from functools import wraps
from typing import Any, Callable, Tuple, cast
import aiomysql
def func_wrapper(func: Callable):
    """和上面一样的封装函数, 这里简单略过"""
# 判断是否hook过
_IS_HOOK: bool = False
# 存放原来的_query
_query: Callable = aiomysql.Cursor._query
# hook函数
def install_hook() -> None:
    _IS_HOOK = False
    if _IS_HOOK:
        return
    aiomysql.Cursor._query = func_wrapper(aiomysql.Cursor._query)
    _IS_HOOK = True
# 还原到原来的函数方法
def reset_hook() -> None:
    aiomysql.Cursor._query = _query
    _IS_HOOK = False
로그인 후 복사

代码简单明了,接下来跑一跑刚才的测试:

import asyncio
import aiomysql
from demo import install_hook, reset_hook
async def test_mysql() -> None:
    pool: aiomysql.Pool = await aiomysql.create_pool(
        host='127.0.0.1', port=3306, user='root', password='', db='mysql'
    )
    async with pool.acquire() as conn:
        async with conn.cursor() as cur:
            await cur.execute("SELECT 42;")
            (r,) = await cur.fetchone()
            assert r == 42
    pool.close()
    await pool.wait_closed()

print("install hook")
install_hook()
asyncio.run(test_mysql())
print("reset hook")
reset_hook()
asyncio.run(test_mysql())
print("end")
로그인 후 복사

通过测试输出可以发现我们的逻辑的正确的, install hook后能出现我们提取的元信息, 而reset后则不会打印原信息

install hook
{'sql': 'SELECT 42;', 'db': 'mysql', 'user': 'root', 'host': '127.0.0.1', 'port': 3306, 'result': ((42,),), 'speed time': 0.000347137451171875}
reset hook
end
로그인 후 복사

위 내용은 Python 프로브는 호출 라이브러리에서 데이터 추출을 어떻게 완료합니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. 크로스 플레이가 있습니까?
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

PHP 및 Python : 코드 예제 및 비교 PHP 및 Python : 코드 예제 및 비교 Apr 15, 2025 am 12:07 AM

PHP와 Python은 고유 한 장점과 단점이 있으며 선택은 프로젝트 요구와 개인 선호도에 달려 있습니다. 1.PHP는 대규모 웹 애플리케이션의 빠른 개발 및 유지 보수에 적합합니다. 2. Python은 데이터 과학 및 기계 학습 분야를 지배합니다.

Python vs. JavaScript : 커뮤니티, 라이브러리 및 리소스 Python vs. JavaScript : 커뮤니티, 라이브러리 및 리소스 Apr 15, 2025 am 12:16 AM

Python과 JavaScript는 커뮤니티, 라이브러리 및 리소스 측면에서 고유 한 장점과 단점이 있습니다. 1) Python 커뮤니티는 친절하고 초보자에게 적합하지만 프론트 엔드 개발 리소스는 JavaScript만큼 풍부하지 않습니다. 2) Python은 데이터 과학 및 기계 학습 라이브러리에서 강력하며 JavaScript는 프론트 엔드 개발 라이브러리 및 프레임 워크에서 더 좋습니다. 3) 둘 다 풍부한 학습 리소스를 가지고 있지만 Python은 공식 문서로 시작하는 데 적합하지만 JavaScript는 MDNWebDocs에서 더 좋습니다. 선택은 프로젝트 요구와 개인적인 이익을 기반으로해야합니다.

Centos에서 Pytorch에 대한 GPU 지원은 어떻습니까? Centos에서 Pytorch에 대한 GPU 지원은 어떻습니까? Apr 14, 2025 pm 06:48 PM

CentOS 시스템에서 Pytorch GPU 가속도를 활성화하려면 Cuda, Cudnn 및 GPU 버전의 Pytorch를 설치해야합니다. 다음 단계는 프로세스를 안내합니다. CUDA 및 CUDNN 설치 CUDA 버전 호환성 결정 : NVIDIA-SMI 명령을 사용하여 NVIDIA 그래픽 카드에서 지원하는 CUDA 버전을보십시오. 예를 들어, MX450 그래픽 카드는 CUDA11.1 이상을 지원할 수 있습니다. Cudatoolkit 다운로드 및 설치 : NVIDIACUDATOOLKIT의 공식 웹 사이트를 방문하여 그래픽 카드에서 지원하는 가장 높은 CUDA 버전에 따라 해당 버전을 다운로드하여 설치하십시오. CUDNN 라이브러리 설치 :

Docker 원리에 대한 자세한 설명 Docker 원리에 대한 자세한 설명 Apr 14, 2025 pm 11:57 PM

Docker는 Linux 커널 기능을 사용하여 효율적이고 고립 된 응용 프로그램 실행 환경을 제공합니다. 작동 원리는 다음과 같습니다. 1. 거울은 읽기 전용 템플릿으로 사용되며, 여기에는 응용 프로그램을 실행하는 데 필요한 모든 것을 포함합니다. 2. Union 파일 시스템 (Unionfs)은 여러 파일 시스템을 스택하고 차이점 만 저장하고 공간을 절약하고 속도를 높입니다. 3. 데몬은 거울과 컨테이너를 관리하고 클라이언트는 상호 작용을 위해 사용합니다. 4. 네임 스페이스 및 CGroup은 컨테이너 격리 및 자원 제한을 구현합니다. 5. 다중 네트워크 모드는 컨테이너 상호 연결을 지원합니다. 이러한 핵심 개념을 이해 함으로써만 Docker를 더 잘 활용할 수 있습니다.

미니 오펜 센토 호환성 미니 오펜 센토 호환성 Apr 14, 2025 pm 05:45 PM

Minio Object Storage : Centos System Minio 하의 고성능 배포는 Go Language를 기반으로 개발 한 고성능 분산 객체 저장 시스템입니다. Amazons3과 호환됩니다. Java, Python, JavaScript 및 Go를 포함한 다양한 클라이언트 언어를 지원합니다. 이 기사는 CentOS 시스템에 대한 Minio의 설치 및 호환성을 간단히 소개합니다. CentOS 버전 호환성 Minio는 다음을 포함하되 이에 국한되지 않는 여러 CentOS 버전에서 확인되었습니다. CentOS7.9 : 클러스터 구성, 환경 준비, 구성 파일 설정, 디스크 파티셔닝 및 미니를 다루는 완전한 설치 안내서를 제공합니다.

Centos에서 Pytorch의 분산 교육을 운영하는 방법 Centos에서 Pytorch의 분산 교육을 운영하는 방법 Apr 14, 2025 pm 06:36 PM

CentOS 시스템에 대한 Pytorch 분산 교육에는 다음 단계가 필요합니다. Pytorch 설치 : 전제는 Python과 PIP가 CentOS 시스템에 설치된다는 것입니다. CUDA 버전에 따라 Pytorch 공식 웹 사이트에서 적절한 설치 명령을 받으십시오. CPU 전용 교육의 경우 다음 명령을 사용할 수 있습니다. PipinStalltorchtorchvisiontorchaudio GPU 지원이 필요한 경우 CUDA 및 CUDNN의 해당 버전이 설치되어 있는지 확인하고 해당 PyTorch 버전을 설치하려면 설치하십시오. 분산 환경 구성 : 분산 교육에는 일반적으로 여러 기계 또는 단일 기계 다중 GPU가 필요합니다. 장소

Centos에서 Pytorch 버전을 선택하는 방법 Centos에서 Pytorch 버전을 선택하는 방법 Apr 14, 2025 pm 06:51 PM

CentOS 시스템에 Pytorch를 설치할 때는 적절한 버전을 신중하게 선택하고 다음 주요 요소를 고려해야합니다. 1. 시스템 환경 호환성 : 운영 체제 : CentOS7 이상을 사용하는 것이 좋습니다. Cuda 및 Cudnn : Pytorch 버전 및 Cuda 버전은 밀접하게 관련되어 있습니다. 예를 들어, pytorch1.9.0은 cuda11.1을 필요로하고 Pytorch2.0.1은 cuda11.3을 필요로합니다. CUDNN 버전도 CUDA 버전과 일치해야합니다. Pytorch 버전을 선택하기 전에 호환 CUDA 및 CUDNN 버전이 설치되었는지 확인하십시오. 파이썬 버전 : Pytorch 공식 지점

파이썬 : 자동화, 스크립팅 및 작업 관리 파이썬 : 자동화, 스크립팅 및 작업 관리 Apr 16, 2025 am 12:14 AM

파이썬은 자동화, 스크립팅 및 작업 관리가 탁월합니다. 1) 자동화 : 파일 백업은 OS 및 Shutil과 같은 표준 라이브러리를 통해 실현됩니다. 2) 스크립트 쓰기 : PSUTIL 라이브러리를 사용하여 시스템 리소스를 모니터링합니다. 3) 작업 관리 : 일정 라이브러리를 사용하여 작업을 예약하십시오. Python의 사용 편의성과 풍부한 라이브러리 지원으로 인해 이러한 영역에서 선호하는 도구가됩니다.

See all articles