web-dev-qa-db-ja.com

マルチプロセッシングを使用した並列投稿リクエストとPython

以下のような小さなコードスニペットがあります。

import requests
import multiprocessing

header = {
'X-Location': 'UNKNOWN',
'X-AppVersion': '2.20.0',
'X-UniqueId': '2397123',
'X-User-Locale': 'en',
'X-Platform': 'Android',
'X-AppId': 'com.my_app',
'Accept-Language': 'en-ID',
'X-PushTokenType': 'GCM',
'X-DeviceToken': 'some_device_token'
}


BASE_URI = 'https://my_server.com/v2/customers/login'

def internet_resource_getter(post_data):
    stuff_got = []

    response = requests.post(BASE_URI, headers=header, json=post_data)
    stuff_got.append(response.json())

    return stuff_got

tokens = [{"my_token":'EAAOZAe8Q2rKYBAu0XETMiCZC0EYAddz4Muk6Luh300PGwGAMh26Bpw3AA6srcxbPWSTATpTLmvhzkUHuercNlZC1vDfL9Kmw3pyoQfpyP2t7NzPAOMCbmCAH6ftXe4bDc4dXgjizqnudfM0D346rrEQot5H0esW3RHGf8ZBRVfTtX8yR0NppfU5LfzNPqlAem9M5ZC8lbFlzKpZAZBOxsaz'},{"my_token":'EAAOZAe8Q2rKYBAKQetLqFwoTM2maZBOMUZA2w5mLmYQi1GpKFGZAxZCaRjv09IfAxxK1amZBE3ab25KzL4Bo9xvubiTkRriGhuivinYBkZAwQpnMZC99CR2FOqbNMmZBvLjZBW7xv6BwSTu3sledpLSGQvPIZBKmTv3930dBH8lazZCs3q0Q5i9CZC8mf8kYeamV9DED1nsg5PQZDZD'}]

pool = multiprocessing.Pool(processes=3)
pool_outputs = pool.map(internet_resource_getter, tokens)
pool.close()
pool.join()

私がやろうとしているのは、エンドポイントに並列POSTリクエストを送信することですが、各POSTは、投稿の本文として異なるトークンを持ちます。

  1. 上記でやりたいことを達成できますか?出力は得られますが、リクエストが並行して送信されたかどうかはわかりません。
  2. 私はgrequestsを知っています。私は(システムで複数のプロセッサを利用する場合のように)真の並列要求を実現したかったので、grequestよりもマルチプロセッシングを選択しました(私が理解している限り、これも並列ではなくマルチスレッドのgeventを使用します)。私の理解はここで正しいですか?
6
qre0ct

複数のPOSTリクエストの並列実行に関心がある場合は、 asyncio または aiohttp を使用することをお勧めします。どちらも次のアイデアを実装しています。並行して実行される非同期タスク。

たとえば、asyncioを使用して次のようなことを行うことができます。

import requests
import asyncio

header = {
    'X-Location': 'UNKNOWN',
    'X-AppVersion': '2.20.0',
    'X-UniqueId': '2397123',
    'X-User-Locale': 'en',
    'X-Platform': 'Android',
    'X-AppId': 'com.my_app',
    'Accept-Language': 'en-ID',
    'X-PushTokenType': 'GCM',
    'X-DeviceToken': 'some_device_token'
}

BASE_URI = 'https://my_server.com/v2/customers/login'


def internet_resource_getter(post_data):
    stuff_got = []

    response = requests.post(BASE_URI, headers=header, json=post_data)

    stuff_got.append(response.json())
    print(stuff_got)
    return stuff_got

tokens = [
    {
        "my_token": 'EAAOZAe8Q2rKYBAu0XETMiCZC0EYAddz4Muk6Luh300PGwGAMh26B'
                    'pw3AA6srcxbPWSTATpTLmvhzkUHuercNlZC1vDfL9Kmw3pyoQfpyP'
                    '2t7NzPAOMCbmCAH6ftXe4bDc4dXgjizqnudfM0D346rrEQot5H0es'
                    'W3RHGf8ZBRVfTtX8yR0NppfU5LfzNPqlAem9M5ZC8lbFlzKpZAZBO'
                    'xsaz'
     },
    {
        "my_token": 'EAAOZAe8Q2rKYBAKQetLqFwoTM2maZBOMUZA2w5mLmYQi1GpKFGZAx'
                    'ZCaRjv09IfAxxK1amZBE3ab25KzL4Bo9xvubiTkRriGhuivinYBkZA'
                    'wQpnMZC99CR2FOqbNMmZBvLjZBW7xv6BwSTu3sledpLSGQvPIZBKmT'
                    'v3930dBH8lazZCs3q0Q5i9CZC8mf8kYeamV9DED1nsg5PQZDZD'
     }
]

loop = asyncio.get_event_loop()

for token in tokens:
    loop.run_in_executor(None, internet_resource_getter, token)

これに注意してください:それらはpython 3.xにのみ存在します。しかし、私の意見では、見た目ははるかに良く簡潔であり、それらが並行して実行されることが保証されています。

6
Yuval Pruss

1)はい、上記のコードは各トークンを要求します。要求が正しく処理されたかどうかを確認する1つの方法は、戻りコードを確認することです。

for response in pool_outputs:
   if response.status_code != 200:
       raise Exception("{} - {}".format(response.status_code, response.text))

2)はい、あなたの理解は健全です。私もgrequestsの代わりにマルチプロセッシング+ requestsコンボを使用しています。

関連:

通常、リクエストを並行して行う場合、何百万ものリクエストを行う場合を除いて、複数のコアの使用に集中する必要はありません。これは、HTTP要求が99%のインターネット応答時間と1%のCPU処理時間であるためです。あなたのコードは同時に複数のリクエストをディスパッチします。これは本当に重要なことです。さらに、恐ろしいGlobalInterpreterLockを調べて、マルチコアアプリケーションに影響するかどうかを確認することもできます。 グローバルインタープリターロック(GIL)とは何ですか?

4
Matt Thomson