コード内でサードパーティのインターフェイスを呼び出す頻度を制限する方法

バックグラウンド

サードパーティのインターフェイスを呼び出すときの一般的な問題は、呼び出し頻度が速すぎることであり、これにより、IP によってブロックされる可能性がある、ブロックされる可能性がある、制限される可能性があるなど、一連の問題が発生します。

ソリューション

最も簡単な方法: 一定期間内の通話頻度を制限する

ratelimit 実装は、API を呼び出す頻度を制御します。

たとえば、次のテスト コードは、マルチスレッド シミュレーション リクエストを使用してtest2()関数を呼び出します。

import time
import threading

def test2():
    time.sleep(3)
    print('调用了函数')


def run_func():
    print('模拟普通请求...')
    test2()


if __name__ == '__main__':
    all_t = []
    for i in range(10):
        t = threading.Thread(target=run_func)
        all_t.append(t)

    for n in all_t:
        n.start()

    for k in all_t:
        k.join()

上記のテストコードでは、起動した10個のスレッドで同時に関数が呼び出されておりtest2()、1秒以内に10回APIをリクエストしていることがわかります。以下では、ratelimitライブラリ制御呼び出しの頻度を導入する必要があります。

import time
from ratelimit import limits

@limits(calls=1, period=1)
def test2():
    time.sleep(3)
    print('调用了函数')

デフォルトでは、15 分以内に 15 件のリクエストが許可され、超過したリクエストは破棄されます。ここで設定すると、calls=1,period=11 秒以内に 1 つのリクエストのみが許可されることになります。

ただし、上記のコードを実行すると、一部のスレッドでエラーが発生しましたratelimit.exception.RateLimitException: too many calls。なぜでしょうか?

ブロッキング待機を増やす

前述の通り、設定時間内にリクエスト数が設定値を超えた場合、他のリクエストは破棄されます。したがって、RateLimitExceptionエラーが返された場合の対処が必要です。

過剰なリクエストをブロックするデコレータを追加する

import time
from functools import wraps

from ratelimit import RateLimitException


def sleep_and_retry(func):
    @wraps(func)
    def wrapper(*args, **kargs):
        while True:
            try:
                return func(*args, **kargs)
            except RateLimitException as exception:
                time.sleep(exception.period_remaining)
    return wrapper

結果

上記のデコレータを追加すると、過剰なリクエストもブロックされ、リクエストが正常に応答できるようになります。

完全なコード

import threading
import time
from functools import wraps

from ratelimit import limits, RateLimitException


def sleep_and_retry(func):
    @wraps(func)
    def wrapper(*args, **kargs):
        while True:
            try:
                return func(*args, **kargs)
            except RateLimitException as exception:
                time.sleep(exception.period_remaining)
    return wrapper


@sleep_and_retry
@limits(calls=1, period=1)
def test2():
    time.sleep(3)
    print('调用了函数')


def run_func():
    print('模拟普通请求...')
    test2()


if __name__ == '__main__':
    all_t = []
    for i in range(10):
        t = threading.Thread(target=run_func)
        all_t.append(t)

    for n in all_t:
        n.start()

    for k in all_t:
        k.join()

おすすめ

転載: blog.csdn.net/qq_42349944/article/details/129880244