Azure İşlevleri'da Python uygulamalarının aktarım hızı performansını geliştirme

Python kullanarak Azure İşlevleri için geliştirme yaparken işlevlerinizin performansını ve bu performansın işlev uygulamanızın ölçeklendiriliş şeklini nasıl etkilediğini anlamanız gerekir. Yüksek performanslı uygulamalar tasarlarken ihtiyaç daha önemlidir. İşlev uygulamalarınızı tasarlarken, yazarken ve yapılandırırken dikkate alınması gereken temel faktörler yatay ölçeklendirme ve aktarım hızı performans yapılandırmalarıdır.

Yatay ölçeklendirme

varsayılan olarak, Azure İşlevleri uygulamanızdaki yükü otomatik olarak izler ve gerektiğinde Python için daha fazla konak örneği oluşturur. Azure İşlevleri, queueTrigger için iletilerin yaşı ve kuyruk boyutu gibi örneklerin ne zaman ekleneceğine karar vermek üzere farklı tetikleyici türleri için yerleşik eşikleri kullanır. Bu eşikler kullanıcı tarafından yapılandırılamaz. Daha fazla bilgi için bkz. Azure İşlevleri'de olay temelli ölçeklendirme.

Aktarım hızı performansını iyileştirme

Varsayılan yapılandırmalar Azure İşlevleri uygulamaların çoğu için uygundur. Ancak, iş yükü profilinize göre yapılandırmalar kullanarak uygulamalarınızın aktarım hızının performansını geliştirebilirsiniz. İlk adım, çalıştırdığınız iş yükünün türünü anlamaktır.

İş yükü türü İşlev uygulaması özellikleri Örnekler
G/Ç bağlı • Uygulamanın birçok eşzamanlı çağrıyı işlemesi gerekir.
• Uygulama, ağ çağrıları ve disk okuma/yazma işlemleri gibi çok sayıda G/Ç olayını işler.
• Web API'leri
CPU'ya bağlı • Uygulama, görüntü yeniden boyutlandırma gibi uzun süre çalışan hesaplamalar yapar.
• Uygulama veri dönüştürme yapar.
• Veri işleme
• Makine öğrenmesi çıkarımı

Gerçek dünya işlev iş yükleri genellikle G/Ç ve CPU bağlı bir karışımı olduğundan, gerçekçi üretim yükleri altında uygulamanın profilini oluşturmanız gerekir.

Performansa özgü yapılandırmalar

İşlev uygulamanızın iş yükü profilini anladıktan sonra, işlevlerinizin aktarım hızı performansını geliştirmek için kullanabileceğiniz yapılandırmalar aşağıdadır.

Zaman Uyumsuz

Python tek iş parçacıklı bir çalışma zamanı olduğundan, Python için bir konak örneği varsayılan olarak bir kerede yalnızca bir işlev çağrısını işleyebilir. Çok sayıda G/Ç olayını işleyen ve/veya G/Ç'ye bağlı olan uygulamalar için, işlevleri zaman uyumsuz olarak çalıştırarak performansı önemli ölçüde geliştirebilirsiniz.

Bir işlevi zaman uyumsuz olarak çalıştırmak için, işlevi doğrudan asyncio ile çalıştıran deyimini kullanınasync def:

async def main():
    await some_nonblocking_socket_io_op()

Aşağıda, aiohttp http istemcisi kullanan HTTP tetikleyicisine sahip bir işlev örneği verilmişti:

import aiohttp

import azure.functions as func

async def main(req: func.HttpRequest) -> func.HttpResponse:
    async with aiohttp.ClientSession() as client:
        async with client.get("PUT_YOUR_URL_HERE") as response:
            return func.HttpResponse(await response.text())

    return func.HttpResponse(body='NotFound', status_code=404)

Anahtar sözcüğü olmayan async bir işlev ThreadPoolExecutor iş parçacığı havuzunda otomatik olarak çalıştırılır:

# Runs in a ThreadPoolExecutor threadpool. Number of threads is defined by PYTHON_THREADPOOL_THREAD_COUNT. 
# The example is intended to show how default synchronous functions are handled.

def main():
    some_blocking_socket_io()

İşlevleri zaman uyumsuz olarak çalıştırmanın tam avantajını elde etmek için kodunuzda kullanılan G/Ç işleminin/kitaplığının da zaman uyumsuz olarak uygulanması gerekir. Zaman uyumsuz olarak tanımlanan işlevlerde zaman uyumlu G/Ç işlemlerinin kullanılması genel performansa zarar verebilir. Kullandığınız kitaplıklarda zaman uyumsuz sürüm uygulanmıyorsa, uygulamanızda olay döngüsünü yöneterek kodunuzu zaman uyumsuz olarak çalıştırmanın avantajını yine de elde edebilirsiniz.

Zaman uyumsuz desenler uygulayan istemci kitaplıklarına birkaç örnek aşağıda verilmiştir:

  • aiohttp - Asyncio için Http istemcisi/sunucusu
  • Akışlar API - Ağ bağlantısıyla çalışmak için üst düzey zaman uyumsuz/beklemeye hazır temel öğeler
  • Janus Kuyruğu - Python için iş parçacığı güvenli zaman uyumsuz kuyruk
  • pyzmq - ZeroMQ için Python bağlamaları
Python çalışanında zaman uyumsuzları anlama

İşlev imzasının önünde tanımladığınızda async , Python işlevi bir eş yordam olarak işaretler. Eş yordam çağırdığınızda, bir olay döngüsüne görev olarak zamanlanabilir. Zaman uyumsuz bir işlevi çağırdığınızda await , olay döngüsüne bir devamlılık kaydeder ve bu da olay döngüsünün bekleme süresi boyunca bir sonraki görevi işlemesine olanak tanır.

Python Çalışanımızda çalışan, olay döngüsünü müşterinin async işleviyle paylaşır ve aynı anda birden çok isteği işleyebilecektir. Müşterilerimizin aiohttp ve pyzmq gibi zaman uyumsuz uyumlu kitaplıklardan yararlanmalarını kesinlikle öneririz. Bu önerilerin uygulanması, zaman uyumlu olarak uygulandığında işlevinizin aktarım hızını bu kitaplıklarla karşılaştırıldığında artırır.

Dekont

İşleviniz herhangi bir await uygulama olmadan olarak async bildirilirse, olay döngüsü engellendiğinden, Python çalışanının eşzamanlı istekleri işlemesini engelleyen işlevinizin performansı ciddi şekilde etkilenir.

Birden çok dil çalışanı işlemi kullanma

Varsayılan olarak her İşlev konak örneğinin tek bir dil çalışanı işlemi vardır. Uygulama ayarını kullanarak konak başına çalışan işlemlerinin sayısını artırabilirsiniz (10'a FUNCTIONS_WORKER_PROCESS_COUNT kadar). Azure İşlevleri daha sonra eş zamanlı işlev çağrılarını bu çalışanlara eşit olarak dağıtmaya çalışır.

CPU bağlı uygulamalarda, dil çalışanlarının sayısını işlev uygulaması başına kullanılabilir çekirdek sayısıyla aynı veya daha yüksek olacak şekilde ayarlamanız gerekir. Daha fazla bilgi edinmek için bkz . Kullanılabilir örnek SKU'ları.

G/Ç'ye bağlı uygulamalar, çalışan işlemlerinin sayısını kullanılabilir çekirdek sayısının ötesinde artırmanın da avantajını elde edebilir. Gerekli bağlam anahtarlarının sayısının artması nedeniyle çalışan sayısını çok yüksek ayarlamanın genel performansı etkileyebileceğini unutmayın.

, FUNCTIONS_WORKER_PROCESS_COUNT Azure İşlevleri talebi karşılamak için uygulamanızın ölçeğini genişletirken oluşturduğu her konak için geçerlidir.

Bir dil çalışanı işlemi içinde en fazla çalışan ayarlama

Zaman uyumsuz bölümünde belirtildiği gibi Python dil çalışanı işlevleri ve eş yordamları farklı şekilde ele alır . Coroutine, dil çalışanının üzerinde çalıştığı olay döngüsü içinde çalıştırılır. Öte yandan, bir işlev çağrısı, dil çalışanı tarafından iş parçacığı olarak tutulan threadPoolExecutor içinde çalıştırılır.

PYTHON_THREADPOOL_THREAD_COUNT uygulama ayarını kullanarak eşitleme işlevlerini çalıştırmak için izin verilen en fazla çalışanın değerini ayarlayabilirsiniz. Bu değer, Python'ın çağrıları zaman uyumsuz olarak yürütmek için çoğu max_worker iş parçacığı havuzunu kullanmasına olanak tanıyan ThreadPoolExecutor nesnesinin bağımsız değişkenini ayarlarmax_worker. , PYTHON_THREADPOOL_THREAD_COUNT İşlevler ana bilgisayarının oluşturduğu her çalışan için geçerlidir ve Python yeni bir iş parçacığının ne zaman oluşturulacağını veya mevcut boşta olan iş parçacığının ne zaman yeniden kullanılması gerektiğine karar verir. Eski Python sürümleri (, 3.8, 3.7ve 3.6) max_worker için değer 1 olarak ayarlanır. Python sürümü 3.9 için olarak max_worker ayarlanır None.

CPU'ya bağlı uygulamalar için ayarı 1'den başlayarak ve iş yükünüzle denemeler yapınken artarak düşük bir sayıya tutmanız gerekir. Bu öneri, bağlam anahtarlarında harcanan süreyi azaltmak ve CPU'ya bağlı görevlerin bitmesini sağlamaktır.

G/Ç'ye bağlı uygulamalarda, her çağrı üzerinde çalışan iş parçacığı sayısını artırarak önemli kazançlar görmeniz gerekir. Python varsayılan değeri (çekirdek sayısı) + 4 ile başlayıp gördüğünüz aktarım hızı değerlerine göre ayarlamalar yapmak tavsiye edilir.

Karma iş yükleri uygulamalarında, aktarım hızını en üst düzeye çıkarmak için hem hem PYTHON_THREADPOOL_THREAD_COUNT de FUNCTIONS_WORKER_PROCESS_COUNT yapılandırmaları dengelemeniz gerekir. İşlev uygulamalarınızın en çok ne üzerinde zaman geçirdiğini anlamak için profil oluşturmanızı ve değerleri davranışlarına göre ayarlamanızı öneririz. Bu uygulama ayarları hakkında bilgi edinmek için bkz . Birden çok çalışan işlemi kullanma.

Dekont

Bu öneriler hem HTTP hem de HTTP ile tetiklenmeyen işlevler için geçerli olsa da, işlev uygulamalarınızdan beklenen performansı elde etmek için HTTP ile tetiklenmeyen işlevler için tetikleyiciye özgü diğer yapılandırmaları ayarlamanız gerekebilir. Bu konuda daha fazla bilgi için lütfen bu Güvenilir Azure İşlevleri için en iyi yöntemler konusuna bakın.

Olay döngüsünü yönetme

Zaman uyumsuz uyumlu üçüncü taraf kitaplıkları kullanmanız gerekir. Üçüncü taraf kitaplıklardan hiçbiri gereksinimlerinizi karşılamıyorsa, Azure İşlevleri olay döngülerini de yönetebilirsiniz. Olay döngülerini yönetmek, işlem kaynağı yönetiminde size daha fazla esneklik sağlar ve zaman uyumlu G/Ç kitaplıklarını eş yordamlara sarmalamanızı da mümkün kılar.

Yerleşik asyncio kitaplığını kullanarak Coroutines ve Görevler ile Olay Döngüsü'nü tartışan birçok yararlı Python resmi belgesi vardır.

Örnek olarak aşağıdaki istek kitaplığını ele alalım, bu kod parçacığı yöntemi eş zamanlı olarak SAMPLE_URL için birden çok web isteği çalıştırarak bir coroutine sarmak requests.get() için asyncio kitaplığını kullanır.

import asyncio
import json
import logging

import azure.functions as func
from time import time
from requests import get, Response


async def invoke_get_request(eventloop: asyncio.AbstractEventLoop) -> Response:
    # Wrap requests.get function into a coroutine
    single_result = await eventloop.run_in_executor(
        None,  # using the default executor
        get,  # each task call invoke_get_request
        'SAMPLE_URL'  # the url to be passed into the requests.get function
    )
    return single_result

async def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    eventloop = asyncio.get_event_loop()

    # Create 10 tasks for requests.get synchronous call
    tasks = [
        asyncio.create_task(
            invoke_get_request(eventloop)
        ) for _ in range(10)
    ]

    done_tasks, _ = await asyncio.wait(tasks)
    status_codes = [d.result().status_code for d in done_tasks]

    return func.HttpResponse(body=json.dumps(status_codes),
                             mimetype='application/json')

Dikey ölçeklendirme

Daha yüksek belirtimlere sahip premium plana yükselterek özellikle CPU'ya bağlı işlemlerde daha fazla işlem birimi elde edebilirsiniz. Daha yüksek işleme birimleriyle çalışan işlemlerinin sayısını kullanılabilir çekirdek sayısına göre ayarlayabilir ve daha yüksek paralellik derecesine ulaşabilirsiniz.

Sonraki adımlar

Python geliştirme Azure İşlevleri hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın: