Introduzione all'SDK di Batch per PythonGet started with the Batch SDK for Python

Questo articolo illustra i concetti di base relativi ad Azure Batch e al client Python di Batch esaminando una piccola applicazione Batch scritta in Python.Learn the basics of Azure Batch and the Batch Python client as we discuss a small Batch application written in Python. Verrà illustrato il modo in cui due script di esempio usano il servizio Batch per elaborare un carico di lavoro parallelo in macchine virtuali Linux nel cloud e come interagiscono con Archiviazione di Azure per lo staging e il recupero di file.We look at how two sample scripts use the Batch service to process a parallel workload on Linux virtual machines in the cloud, and how they interact with Azure Storage for file staging and retrieval. Saranno disponibili informazioni su un flusso di lavoro comune dell'applicazione Batch e sui principali componenti di Batch, ad esempio processi, attività, pool e nodi di calcolo.You'll learn a common Batch application workflow and gain a base understanding of the major components of Batch such as jobs, tasks, pools, and compute nodes.

Flusso di lavoro della soluzione Batch (di base)Batch solution workflow (basic)

PrerequisitiPrerequisites

Questo articolo presuppone che l'utente sappia usare Python e LinuxThis article assumes that you have a working knowledge of Python and familiarity with Linux. e possa soddisfare i requisiti di creazione dell'account specificati di seguito per Azure e per i servizi Batch e di archiviazione.It also assumes that you're able to satisfy the account creation requirements that are specified below for Azure and the Batch and Storage services.

AccountAccounts

Esempio di codiceCode sample

L'esempio di codice Python usato nell'esercitazione è uno dei molti esempi di codice Batch disponibili nel repository azure-batch-samples in GitHub.The Python tutorial code sample is one of the many Batch code samples found in the azure-batch-samples repository on GitHub. È possibile scaricare tutti gli esempi facendo clic su Clone or download > Download ZIP (Clona o scarica > Scarica ZIP) nella home page del repository oppure facendo clic sul collegamento di download diretto azure-batch-samples-master.zip.You can download all the samples by clicking Clone or download > Download ZIP on the repository home page, or by clicking the azure-batch-samples-master.zip direct download link. Dopo aver estratto il contenuto del file ZIP, i due script per questa esercitazione sono disponibili nella directory article_samples :Once you've extracted the contents of the ZIP file, the two scripts for this tutorial are found in the article_samples directory:

/azure-batch-samples/Python/Batch/article_samples/python_tutorial_client.py
/azure-batch-samples/Python/Batch/article_samples/python_tutorial_task.py

Ambiente PythonPython environment

Per eseguire lo script di esempio python_tutorial_client.py nella workstation locale è necessario un interprete Python compatibile con la versione 2.7 o 3.3+.To run the python_tutorial_client.py sample script on your local workstation, you need a Python interpreter compatible with version 2.7 or 3.3+. Lo script è stato verificato in ambiente Linux e Windows.The script has been tested on both Linux and Windows.

Dipendenze di cryptographycryptography dependencies

È necessario installare le dipendenze per la libreria cryptography, richieste dai pacchetti Python azure-batch e azure-storage.You must install the dependencies for the cryptography library, required by the azure-batch and azure-storage Python packages. Eseguire una di queste operazioni appropriate per la piattaforma o vedere i dettagli dell'installazione di cryptography per altre informazioni:Perform one of the following operations appropriate for your platform, or refer to the cryptography installation details for more information:

  • UbuntuUbuntu

    apt-get update && apt-get install -y build-essential libssl-dev libffi-dev libpython-dev python-dev

  • CentOSCentOS

    yum update && yum install -y gcc openssl-devel libffi-devel python-devel

  • SLES/OpenSUSESLES/OpenSUSE

    zypper ref && zypper -n in libopenssl-dev libffi48-devel python-devel

  • WindowsWindows

    pip install cryptography

Nota

Se si esegue l'installazione per Python 3.3+ in Linux, usare gli equivalenti di python3 per le dipendenze di Python.If installing for Python 3.3+ on Linux, use the python3 equivalents for the Python dependencies. Ad esempio, in Ubuntu: apt-get update && apt-get install -y build-essential libssl-dev libffi-dev libpython3-dev python3-devFor example, on Ubuntu: apt-get update && apt-get install -y build-essential libssl-dev libffi-dev libpython3-dev python3-dev

Pacchetti di AzureAzure packages

Installare poi i pacchetti Python per Azure Batch e Archiviazione di Azure.Next, install the Azure Batch and Azure Storage Python packages. È possibile installare entrambi i pacchetti usando pip e requirements.txt disponibili qui:You can install both packages by using pip and the requirements.txt found here:

/azure-batch-samples/Python/Batch/requirements.txt

Per installare i pacchetti per Batch e Archiviazione, eseguire il comando pip seguente:Issue following pip command to install the Batch and Storage packages:

pip install -r requirements.txt

In alternativa, è possibile installare i pacchetti Python azure-batch e azure-storage manualmente:Or, you can install the azure-batch and azure-storage Python packages manually:

pip install azure-batch
pip install azure-storage

Suggerimento

Se si una un account senza privilegi, può essere necessario anteporre sudo ai comandi.If you are using an unprivileged account, you may need to prefix your commands with sudo. Ad esempio: sudo pip install -r requirements.txt.For example, sudo pip install -r requirements.txt. Per altre informazioni sull'installazione dei pacchetti Python, vedere Installing Packages (Installazione di pacchetti) in python.org.For more information on installing Python packages, see Installing Packages on python.org.

Esempio di codice per l'esercitazione di Batch PythonBatch Python tutorial code sample

L'esempio di codice per l'esercitazione di Batch Python è costituito da due script Python e alcuni file di dati.The Batch Python tutorial code sample consists of two Python scripts and a few data files.

  • python_tutorial_client.py: interagisce con i servizi Batch e Archiviazione per eseguire un carico di lavoro parallelo nei nodi di calcolo (macchine virtuali).python_tutorial_client.py: Interacts with the Batch and Storage services to execute a parallel workload on compute nodes (virtual machines). Lo script python_tutorial_client.py viene eseguito nella workstation locale.The python_tutorial_client.py script runs on your local workstation.
  • python_tutorial_task.py: script eseguito nei nodi di calcolo in Azure per completare le operazioni effettive.python_tutorial_task.py: The script that runs on compute nodes in Azure to perform the actual work. Nell'esempio python_tutorial_task.py analizza il testo in un file scaricato da Archiviazione di Azure (file di input).In the sample, python_tutorial_task.py parses the text in a file downloaded from Azure Storage (the input file). Produce quindi un file di testo (file di output) che contiene un elenco delle prime tre parole visualizzate nel file di input.Then it produces a text file (the output file) that contains a list of the top three words that appear in the input file. Dopo aver creato il file di output, python_tutorial_task.py carica il file in Archiviazione di Azure.After it creates the output file, python_tutorial_task.py uploads the file to Azure Storage. Questo lo rende disponibile per il download nello script client in esecuzione nella workstation.This makes it available for download to the client script running on your workstation. Lo script python_tutorial_task.py viene eseguito in parallelo in più nodi di calcolo nel servizio Batch.The python_tutorial_task.py script runs in parallel on multiple compute nodes in the Batch service.
  • ./data/taskdata*.txt: questi tre file di testo forniscono l'input per le attività eseguite nei nodi di calcolo../data/taskdata*.txt: These three text files provide the input for the tasks that run on the compute nodes.

Il diagramma seguente illustra le operazioni principali eseguite dagli script client e attività.The following diagram illustrates the primary operations that are performed by the client and task scripts. Questo flusso di lavoro di base è tipico di molte soluzioni di calcolo create con Batch.This basic workflow is typical of many compute solutions that are created with Batch. Anche se non illustra ogni funzionalità disponibile nel servizio Batch, quasi tutti gli scenari di Batch includono parti di questo flusso di lavoro.While it does not demonstrate every feature available in the Batch service, nearly every Batch scenario includes portions of this workflow.

Flusso di lavoro dell'esempio di BatchBatch example workflow

Passaggio 1.Step 1. Creare contenitori nell'archivio BLOB di Azure.Create containers in Azure Blob Storage.
Passaggio 2. Step 2. Caricare lo script attività e i file di input nei contenitori.Upload task script and input files to containers.
Passaggio 3. Step 3. Creare un pool di Batch.Create a Batch pool.
    3a.    3a. L'attività StartTask del pool scarica lo script attività (python_tutorial_task.py) nei nodi quando questi vengono aggiunti al pool.The pool StartTask downloads the task script (python_tutorial_task.py) to nodes as they join the pool.
Passaggio 4. Step 4. Creare un processo di Batch.Create a Batch job.
Passaggio 5. Step 5. Aggiungere attività al processo.Add tasks to the job.
    5a.    5a. Viene pianificata l'esecuzione delle attività nei nodi.The tasks are scheduled to execute on nodes.
    5b.    5b. Ogni attività scarica i rispettivi dati di input da Archiviazione di Azure e quindi avvia l'esecuzione.Each task downloads its input data from Azure Storage, then begins execution.
Passaggio 6. Step 6. Monitorare le attività.Monitor tasks.
    6a.    6a. Dopo il completamento, le attività caricano i rispettivi dati di output in Archiviazione di Azure.As tasks are completed, they upload their output data to Azure Storage.
Passaggio 7. Step 7. Scaricare l'output delle attività dal servizio di archiviazione.Download task output from Storage.

Come indicato, non tutte le soluzioni Batch eseguono esattamente questi passaggi e potrebbero includerne molti altri, ma l'esempio illustra i processi comuni presenti in una soluzione Batch.As mentioned, not every Batch solution performs these exact steps, and may include many more, but this sample demonstrates common processes found in a Batch solution.

Preparare lo script clientPrepare client script

Prima di eseguire l'esempio, aggiungere le credenziali dell'account Batch e dell'account di archiviazione a python_tutorial_client.py.Before you run the sample, add your Batch and Storage account credentials to python_tutorial_client.py. Se non è già stato fatto, aprire il file in un editor qualsiasi e aggiornare le righe seguenti con le credenziali.If you have not done so already, open the file in your favorite editor and update the following lines with your credentials.

# Update the Batch and Storage account credential strings below with the values
# unique to your accounts. These are used when constructing connection strings
# for the Batch and Storage client objects.

# Batch account credentials
BATCH_ACCOUNT_NAME = ""
BATCH_ACCOUNT_KEY = ""
BATCH_ACCOUNT_URL = ""

# Storage account credentials
STORAGE_ACCOUNT_NAME = ""
STORAGE_ACCOUNT_KEY = ""

Le credenziali dell'account Batch e dell'account di archiviazione sono disponibili nel pannello dell'account di ogni servizio nel portale di Azure:You can find your Batch and Storage account credentials within the account blade of each service in the Azure portal:

Credenziali di Batch nel portale Credenziali di archiviazione nel portaleBatch credentials in the portal Storage credentials in the portal

Nelle sezioni seguenti verranno analizzati i passaggi usati dagli script per elaborare un carico di lavoro nel servizio Batch.In the following sections, we analyze the steps used by the scripts to process a workload in the Batch service. È consigliabile fare sempre riferimento agli script nell'editor durante la lettura dell'articolo.We encourage you to refer regularly to the scripts in your editor while you work your way through the rest of the article.

Passare alla riga seguente in python_tutorial_client.py per iniziare con il passaggio 1:Navigate to the following line in python_tutorial_client.py to start with Step 1:

if __name__ == '__main__':

Passaggio 1: Creare contenitori di archiviazioneStep 1: Create Storage containers

Creare contenitori in Archiviazione di Azure Create containers in Azure Storage

Batch include il supporto predefinito per l'interazione con Archiviazione di Azure.Batch includes built-in support for interacting with Azure Storage. I contenitori nell'account di archiviazione forniranno i file necessari per le attività eseguite nell'account Batch,Containers in your Storage account will provide the files needed by the tasks that run in your Batch account. oltre a una posizione in cui archiviare i dati di output prodotti.The containers also provide a place to store the output data that the tasks produce. La prima operazione eseguita dallo script python_tutorial_client.py consiste nel creare tre contenitori nell'archivio BLOB di Azure:The first thing the python_tutorial_client.py script does is create three containers in Azure Blob Storage:

  • application: in questo contenitore verrà archiviato lo script Python eseguito dalle attività, python_tutorial_task.py.application: This container will store the Python script run by the tasks, python_tutorial_task.py.
  • input: le attività scaricheranno i file di dati da elaborare dal contenitore input .input: Tasks will download the data files to process from the input container.
  • output: dopo aver completato l'elaborazione dei file di input, le attività caricheranno i risultati nel contenitore output .output: When tasks complete input file processing, they will upload the results to the output container.

Per interagire con un account di archiviazione e creare contenitori, viene usato il pacchetto azure-storage per creare un oggetto BlockBlobService, ovvero il "client BLOB".In order to interact with a Storage account and create containers, we use the azure-storage package to create a BlockBlobService object--the "blob client." Verranno quindi creati tre contenitori nell'account di archiviazione usando il client BLOB.We then create three containers in the Storage account using the blob client.

import azure.storage.blob as azureblob

# Create the blob client, for use in obtaining references to
# blob storage containers and uploading files to containers.
blob_client = azureblob.BlockBlobService(
    account_name=STORAGE_ACCOUNT_NAME,
    account_key=STORAGE_ACCOUNT_KEY)

# Use the blob client to create the containers in Azure Storage if they
# don't yet exist.
APP_CONTAINER_NAME = 'application'
INPUT_CONTAINER_NAME = 'input'
OUTPUT_CONTAINER_NAME = 'output'
blob_client.create_container(APP_CONTAINER_NAME, fail_on_exist=False)
blob_client.create_container(INPUT_CONTAINER_NAME, fail_on_exist=False)
blob_client.create_container(OUTPUT_CONTAINER_NAME, fail_on_exist=False)

Dopo la creazione dei contenitori, l'applicazione può caricare i file che verranno usati dalle attività.Once the containers have been created, the application can now upload the files that will be used by the tasks.

Suggerimento

Come usare l'archiviazione BLOB di Azure da Python offre utili informazioni generali sull'uso dei contenitori e dei BLOB di Archiviazione di Azure,How to use Azure Blob storage from Python provides a good overview of working with Azure Storage containers and blobs. quindi è consigliabile prenderne visione quando si inizia a usare Batch.It should be near the top of your reading list as you start working with Batch.

Passaggio 2: Caricare lo script attività e i file di datiStep 2: Upload task script and data files

Caricare l'applicazione dell'attività e i file di input (dati) nei contenitori Upload task application and input (data) files to containers

Nell'operazione di caricamento dei file python_tutorial_client.py definisce prima di tutto le raccolte dei percorsi di file di application e input esistenti nel computer locale,In the file upload operation, python_tutorial_client.py first defines collections of application and input file paths as they exist on the local machine. quindi carica i file nei contenitori creati nel passaggio precedente.Then it uploads these files to the containers that you created in the previous step.

# Paths to the task script. This script will be executed by the tasks that
# run on the compute nodes.
application_file_paths = [os.path.realpath('python_tutorial_task.py')]

# The collection of data files that are to be processed by the tasks.
input_file_paths = [os.path.realpath('./data/taskdata1.txt'),
                    os.path.realpath('./data/taskdata2.txt'),
                    os.path.realpath('./data/taskdata3.txt')]

# Upload the application script to Azure Storage. This is the script that
# will process the data files, and is executed by each of the tasks on the
# compute nodes.
application_files = [
    upload_file_to_container(blob_client, APP_CONTAINER_NAME, file_path)
    for file_path in application_file_paths]

# Upload the data files. This is the data that will be processed by each of
# the tasks executed on the compute nodes in the pool.
input_files = [
    upload_file_to_container(blob_client, INPUT_CONTAINER_NAME, file_path)
    for file_path in input_file_paths]

Con la comprensione di lista, la funzione upload_file_to_container viene chiamata per ogni file presente nelle raccolte e vengono popolate due raccolte ResourceFile.Using list comprehension, the upload_file_to_container function is called for each file in the collections, and two ResourceFile collections are populated. La funzione upload_file_to_container è riportata di seguito:The upload_file_to_container function appears below:

def upload_file_to_container(block_blob_client, container_name, path):
    """
    Uploads a local file to an Azure Blob storage container.

    :param block_blob_client: A blob service client.
    :type block_blob_client: `azure.storage.blob.BlockBlobService`
    :param str container_name: The name of the Azure Blob storage container.
    :param str file_path: The local path to the file.
    :rtype: `azure.batch.models.ResourceFile`
    :return: A ResourceFile initialized with a SAS URL appropriate for Batch
    tasks.
    """

    import datetime
    import azure.storage.blob as azureblob
    import azure.batch.models as batchmodels

    blob_name = os.path.basename(path)

    print('Uploading file {} to container [{}]...'.format(path,
                                                          container_name))

    block_blob_client.create_blob_from_path(container_name,
                                            blob_name,
                                            file_path)

    sas_token = block_blob_client.generate_blob_shared_access_signature(
        container_name,
        blob_name,
        permission=azureblob.BlobPermissions.READ,
        expiry=datetime.datetime.utcnow() + datetime.timedelta(hours=2))

    sas_url = block_blob_client.make_blob_url(container_name,
                                              blob_name,
                                              sas_token=sas_token)

    return batchmodels.ResourceFile(file_path=blob_name,
                                    blob_source=sas_url)

ResourceFilesResourceFiles

Un oggetto ResourceFile fornisce alle attività in Batch l'URL di un file in Archiviazione di Azure che verrà scaricato in un nodo di calcolo prima dell'esecuzione dell'attività.A ResourceFile provides tasks in Batch with the URL to a file in Azure Storage that is downloaded to a compute node before that task is run. La proprietà ResourceFile.blob_source specifica l'URL completo del file esistente in Archiviazione di Azure,The ResourceFile.blob_source property specifies the full URL of the file as it exists in Azure Storage. che può includere anche una firma di accesso condiviso che fornisce l'accesso sicuro al file.The URL may also include a shared access signature (SAS) that provides secure access to the file. La maggior parte dei tipi di attività in Batch include una proprietà ResourceFiles, ad esempio:Most task types in Batch include a ResourceFiles property, including:

Questo esempio non usa i tipi di attività JobPreparationTask o JobReleaseTask, ma altre informazioni in merito sono disponibili in Eseguire attività di preparazione e completamento di processi in nodi di calcolo di Azure Batch.This sample does not use the JobPreparationTask or JobReleaseTask task types, but you can read more about them in Run job preparation and completion tasks on Azure Batch compute nodes.

Firma di accesso condivisoShared access signature (SAS)

Le firme di accesso condiviso sono stringhe che consentono l'accesso sicuro a contenitori e BLOB in Archiviazione di Azure.Shared access signatures are strings that provide secure access to containers and blobs in Azure Storage. Lo script python_tutorial_client.py usa firme di accesso condiviso per BLOB e contenitori e illustra come ottenere queste stringhe di firma di accesso condiviso dal servizio Archiviazione.The python_tutorial_client.py script uses both blob and container shared access signatures, and demonstrates how to obtain these shared access signature strings from the Storage service.

  • Firme di accesso condiviso per BLOB: l'attività StartTask del pool usa le firme di accesso condiviso dei BLOB durante il download dello script attività e dei file di dati di input da Archiviazione, come illustrato più avanti nel passaggio 3 .Blob shared access signatures: The pool's StartTask uses blob shared access signatures when it downloads the task script and input data files from Storage (see Step #3 below). La funzione upload_file_to_container in python_tutorial_client.py contiene il codice che ottiene la firma di accesso condiviso di ogni BLOB.The upload_file_to_container function in python_tutorial_client.py contains the code that obtains each blob's shared access signature. L'operazione viene eseguita chiamando BlockBlobService.make_blob_url nel modulo di archiviazione.It does so by calling BlockBlobService.make_blob_url in the Storage module.
  • Firma di accesso condiviso per contenitori: quando completa le operazioni sul nodo di calcolo, ogni attività carica il rispettivo file di output nel contenitore output in Archiviazione di Azure.Container shared access signature: As each task finishes its work on the compute node, it uploads its output file to the output container in Azure Storage. A tale scopo, python_tutorial_task.py usa una firma di accesso condiviso del contenitore che fornisce l'accesso in scrittura al contenitore stesso.To do so, python_tutorial_task.py uses a container shared access signature that provides write access to the container. La funzione get_container_sas_token in python_tutorial_client.py ottiene la firma di accesso condiviso del contenitore, che viene quindi passata alle attività come argomento della riga di comando.The get_container_sas_token function in python_tutorial_client.py obtains the container's shared access signature, which is then passed as a command-line argument to the tasks. Il passaggio 5, Aggiungere attività a un processo, illustra l'utilizzo della firma di accesso condiviso del contenitore.Step #5, Add tasks to a job, discusses the usage of the container SAS.

Suggerimento

Per altre informazioni su come fornire un accesso sicuro ai dati nell'account di archiviazione, vedere la serie in due parti sulle firme di accesso condiviso, Parte 1: Informazioni sul modello di firma di accesso condiviso e Parte 2: Creare e usare una firma di accesso condiviso con il servizio BLOB.Check out the two-part series on shared access signatures, Part 1: Understanding the SAS model and Part 2: Create and use a SAS with the Blob service, to learn more about providing secure access to data in your Storage account.

Passaggio 3: Creare un pool di BatchStep 3: Create Batch pool

Creare un pool di Batch Create a Batch pool

Un pool di Batch è una raccolta di nodi di calcolo (macchine virtuali) in cui Batch esegue le attività di un processo.A Batch pool is a collection of compute nodes (virtual machines) on which Batch executes a job's tasks.

Dopo il caricamento dello script attività e dei file di dati nell'account di archiviazione, python_tutorial_client.py avvia l'interazione con il servizio Batch usando il modulo Batch Python.After it uploads the task script and data files to the Storage account, python_tutorial_client.py starts its interaction with the Batch service by using the Batch Python module. A tale scopo viene creato un oggetto BatchServiceClient:To do so, a BatchServiceClient is created:

# Create a Batch service client. We'll now be interacting with the Batch
# service in addition to Storage.
credentials = batchauth.SharedKeyCredentials(BATCH_ACCOUNT_NAME,
                                             BATCH_ACCOUNT_KEY)

batch_client = batch.BatchServiceClient(
    credentials,
    base_url=BATCH_ACCOUNT_URL)

Viene quindi creato un pool di nodi di calcolo nell'account Batch con una chiamata a create_pool.Next, a pool of compute nodes is created in the Batch account with a call to create_pool.

def create_pool(batch_service_client, pool_id,
                resource_files, publisher, offer, sku):
    """
    Creates a pool of compute nodes with the specified OS settings.

    :param batch_service_client: A Batch service client.
    :type batch_service_client: `azure.batch.BatchServiceClient`
    :param str pool_id: An ID for the new pool.
    :param list resource_files: A collection of resource files for the pool's
    start task.
    :param str publisher: Marketplace image publisher
    :param str offer: Marketplace image offer
    :param str sku: Marketplace image sku
    """
    print('Creating pool [{}]...'.format(pool_id))

    # Create a new pool of Linux compute nodes using an Azure Virtual Machines
    # Marketplace image. For more information about creating pools of Linux
    # nodes, see:
    # https://azure.microsoft.com/documentation/articles/batch-linux-nodes/

    # Specify the commands for the pool's start task. The start task is run
    # on each node as it joins the pool, and when it's rebooted or re-imaged.
    # We use the start task to prep the node for running our task script.
    task_commands = [
        # Copy the python_tutorial_task.py script to the "shared" directory
        # that all tasks that run on the node have access to.
        'cp -r $AZ_BATCH_TASK_WORKING_DIR/* $AZ_BATCH_NODE_SHARED_DIR',
        # Install pip and the dependencies for cryptography
        'apt-get update',
        'apt-get -y install python-pip',
        'apt-get -y install build-essential libssl-dev libffi-dev python-dev',
        # Install the azure-storage module so that the task script can access
        # Azure Blob storage
        'pip install azure-storage']

    # Get the node agent SKU and image reference for the virtual machine
    # configuration.
    # For more information about the virtual machine configuration, see:
    # https://azure.microsoft.com/documentation/articles/batch-linux-nodes/
    sku_to_use, image_ref_to_use = \
        common.helpers.select_latest_verified_vm_image_with_node_agent_sku(
            batch_service_client, publisher, offer, sku)

    new_pool = batch.models.PoolAddParameter(
        id=pool_id,
        virtual_machine_configuration=batchmodels.VirtualMachineConfiguration(
            image_reference=image_ref_to_use,
            node_agent_sku_id=sku_to_use),
        vm_size=_POOL_VM_SIZE,
        target_dedicated=_POOL_NODE_COUNT,
        start_task=batch.models.StartTask(
            command_line=
            common.helpers.wrap_commands_in_shell('linux', task_commands),
            run_elevated=True,
            wait_for_success=True,
            resource_files=resource_files),
        )

    try:
        batch_service_client.pool.add(new_pool)
    except batchmodels.batch_error.BatchErrorException as err:
        print_batch_exception(err)
        raise

Quando si crea un pool, si definisce un elemento PoolAddParameter che specifica diverse proprietà per il pool:When you create a pool, you define a PoolAddParameter that specifies several properties for the pool:

  • ID del pool (id: obbligatorio)ID of the pool (id - required)

    Così come la maggior parte delle entità in Batch, il nuovo pool deve avere un ID univoco all'interno dell'account Batch.As with most entities in Batch, your new pool must have a unique ID within your Batch account. Il codice fa riferimento a questo pool usando il relativo ID, che costituisce anche il modo con cui si identifica il pool nel portale di Azure.Your code refers to this pool using its ID, and it's how you identify the pool in the Azure portal.

  • Numero di nodi di calcolo (target_dedicated: obbligatorio)Number of compute nodes (target_dedicated - required)

    Questa proprietà specifica il numero di macchine virtuali da distribuire nel pool.This property specifies how many VMs should be deployed in the pool. È importante notare che tutti gli account Batch hanno una quota predefinita che limita il numero di core e di conseguenza di nodi di calcolo in un account Batch.It is important to note that all Batch accounts have a default quota that limits the number of cores (and thus, compute nodes) in a Batch account. Le quote predefinite e le istruzioni su come aumentare una quota, ad esempio il numero massimo di core nell'account Batch, sono riportate in Quote e limiti per il servizio Azure Batch.You can find the default quotas and instructions on how to increase a quota (such as the maximum number of cores in your Batch account) in Quotas and limits for the Azure Batch service. Se il pool non raggiunge più di X nodi, ad esempio,If you find yourself asking "Why won't my pool reach more than X nodes?" questa quota di core può essere la causa.this core quota may be the cause.

  • Sistema operativo per i nodi (virtual_machine_configuration o cloud_service_configuration: obbligatorio)Operating system for nodes (virtual_machine_configuration or cloud_service_configuration - required)

    In python_tutorial_client.py viene creato un pool di nodi Linux tramite VirtualMachineConfiguration.In python_tutorial_client.py, we create a pool of Linux nodes using a VirtualMachineConfiguration. La funzione select_latest_verified_vm_image_with_node_agent_sku in common.helpers semplifica l'uso delle immagini di Marketplace per Macchine virtuali di Azure.The select_latest_verified_vm_image_with_node_agent_sku function in common.helpers simplifies working with Azure Virtual Machines Marketplace images. Per altre informazioni sull'uso delle immagini del Marketplace, vedere Effettuare il provisioning di nodi di calcolo Linux nei pool di Azure Batch .See Provision Linux compute nodes in Azure Batch pools for more information about using Marketplace images.

  • Dimensione dei nodi di calcolo (vm_size: obbligatorio)Size of compute nodes (vm_size - required)

    Dato che vengono specificati nodi Linux per VirtualMachineConfiguration, viene specificata una dimensione di VM, in questo esempio STANDARD_A1, in base a quanto descritto in Dimensioni delle macchine virtuali in Azure.Since we're specifying Linux nodes for our VirtualMachineConfiguration, we specify a VM size (STANDARD_A1 in this sample) from Sizes for virtual machines in Azure. Per altre informazioni, vedere Effettuare il provisioning di nodi di calcolo Linux nei pool di Azure Batch .Again, see Provision Linux compute nodes in Azure Batch pools for more information.

  • Attività di avvio (start_task: non obbligatorio)Start task (start_task - not required)

    Oltre alle proprietà relative ai nodi fisici sopra descritte, è possibile specificare anche un elemento StartTask per il pool, ma non è obbligatorio.Along with the above physical node properties, you may also specify a StartTask for the pool (it is not required). L'attività StartTask viene eseguita in ogni nodo quando questo viene aggiunto al pool e ogni volta che viene riavviato.The StartTask executes on each node as that node joins the pool, and each time a node is restarted. StartTask è particolarmente utile per preparare i nodi di calcolo per l'esecuzione di attività, ad esempio per installare le applicazioni che vengono eseguite dalle attività.The StartTask is especially useful for preparing compute nodes for the execution of tasks, such as installing the applications that your tasks run.

    In questa applicazione di esempio StartTask copia i file scaricati dal servizio di archiviazione, specificati usando la proprietà resource_files di StartTask, dalla directory di lavoro di StartTask alla directory condivisa a cui possono accedere tutte le attività in esecuzione sul nodo.In this sample application, the StartTask copies the files that it downloads from Storage (which are specified by using the StartTask's resource_files property) from the StartTask working directory to the shared directory that all tasks running on the node can access. Sostanzialmente, viene copiato python_tutorial_task.py nella directory condivisa in ogni nodo quando questo viene aggiunto al pool, in modo che qualsiasi attività in esecuzione nel nodo possa accedervi.Essentially, this copies python_tutorial_task.py to the shared directory on each node as the node joins the pool, so that any tasks that run on the node can access it.

Si noti la chiamata alla funzione helper wrap_commands_in_shell .You may notice the call to the wrap_commands_in_shell helper function. Questa funzione acquisisce una raccolta di comandi separati e crea una singola riga di comando appropriata per la proprietà della riga di comando dell'attività.This function takes a collection of separate commands and creates a single command line appropriate for a task's command-line property.

Nel frammento di codice precedente si può notare anche l'uso di due variabili di ambiente nella proprietà command_line di StartTask: AZ_BATCH_TASK_WORKING_DIR e AZ_BATCH_NODE_SHARED_DIR.Also notable in the code snippet above is the use of two environment variables in the command_line property of the StartTask: AZ_BATCH_TASK_WORKING_DIR and AZ_BATCH_NODE_SHARED_DIR. Ogni nodo di calcolo in un pool di Batch viene configurato automaticamente con diverse variabili di ambiente specifiche per Batch.Each compute node within a Batch pool is automatically configured with several environment variables that are specific to Batch. Tutti processi eseguiti da un'attività possono accedere a queste variabili di ambiente.Any process that is executed by a task has access to these environment variables.

Suggerimento

Per altre informazioni sulle variabili di ambiente disponibili nei nodi di calcolo di un pool di Batch, oltre a informazioni sulle directory di lavoro delle attività, vedere Impostazioni di ambiente per le attività e File e directory in Panoramica delle funzionalità di Batch per sviluppatori.To find out more about the environment variables that are available on compute nodes in a Batch pool, as well as information on task working directories, see Environment settings for tasks and Files and directories in the overview of Azure Batch features.

Passaggio 4: Creare un processo di BatchStep 4: Create Batch job

Creare un processo di BatchCreate Batch job

Un processo di Batch è una raccolta di attività ed è associato a un pool di nodi di calcolo.A Batch job is a collection of tasks, and is associated with a pool of compute nodes. Le attività in un processo vengono eseguite nei nodi di calcolo del pool associato.The tasks in a job execute on the associated pool's compute nodes.

È possibile usare un processo non solo per organizzare le attività nei carichi di lavoro correlati e tenerne traccia, ma anche per imporre determinati vincoli, ad esempio il tempo di esecuzione massimo per il processo e, per estensione, per le rispettive attività, nonché per imporre la priorità dei processi rispetto ad altri nell'account Batch.You can use a job not only for organizing and tracking tasks in related workloads, but also for imposing certain constraints--such as the maximum runtime for the job (and by extension, its tasks) and job priority in relation to other jobs in the Batch account. In questo esempio, tuttavia, il processo viene associato solo al pool creato nel Passaggio 3.In this example, however, the job is associated only with the pool that was created in step #3. Non vengono configurate proprietà aggiuntive.No additional properties are configured.

Tutti i processi di Batch sono associati a un pool specifico.All Batch jobs are associated with a specific pool. Questa associazione indica i nodi in cui verranno eseguite le attività del processo.This association indicates which nodes the job's tasks execute on. Il pool viene specificato con la proprietà PoolInformation, come illustrato nel frammento di codice seguente.You specify the pool by using the PoolInformation property, as shown in the code snippet below.

def create_job(batch_service_client, job_id, pool_id):
    """
    Creates a job with the specified ID, associated with the specified pool.

    :param batch_service_client: A Batch service client.
    :type batch_service_client: `azure.batch.BatchServiceClient`
    :param str job_id: The ID for the job.
    :param str pool_id: The ID for the pool.
    """
    print('Creating job [{}]...'.format(job_id))

    job = batch.models.JobAddParameter(
        job_id,
        batch.models.PoolInformation(pool_id=pool_id))

    try:
        batch_service_client.job.add(job)
    except batchmodels.batch_error.BatchErrorException as err:
        print_batch_exception(err)
        raise

Dopo la creazione di un processo, vengono aggiunte attività per l'esecuzione delle operazioni.Now that a job has been created, tasks are added to perform the work.

Passaggio 5: Aggiungere attività a un processoStep 5: Add tasks to job

Aggiungere attività a un processoAdd tasks to job
(1) Le attività vengono aggiunte al processo, (2) viene pianificata l'esecuzione delle attività nei nodi e (3) le attività scaricano i file di dati da elaborare (1) Tasks are added to the job, (2) the tasks are scheduled to run on nodes, and (3) the tasks download the data files to process

Le attività di Batch sono le singole unità di lavoro eseguite nei nodi di calcolo.Batch tasks are the individual units of work that execute on the compute nodes. Un'attività ha una riga di comando ed esegue gli script o i file eseguibili specificati in questa riga di comando.A task has a command line and runs the scripts or executables that you specify in that command line.

Per eseguire effettivamente le operazioni, è necessario aggiungere attività a un processo.To actually perform work, tasks must be added to a job. Ogni elemento CloudTask viene configurato con una proprietà della riga di comando e, analogamente all'attività StartTask del pool, con oggetti ResourceFiles scaricati dall'attività nel nodo prima dell'esecuzione automatica della rispettiva riga di comando.Each CloudTask is configured with a command-line property and ResourceFiles (as with the pool's StartTask) that the task downloads to the node before its command line is automatically executed. Nell'esempio, ogni attività elabora un solo file.In the sample, each task processes only one file. Di conseguenza, la rispettiva raccolta ResourceFiles contiene un singolo elemento.Thus, its ResourceFiles collection contains a single element.

def add_tasks(batch_service_client, job_id, input_files,
              output_container_name, output_container_sas_token):
    """
    Adds a task for each input file in the collection to the specified job.

    :param batch_service_client: A Batch service client.
    :type batch_service_client: `azure.batch.BatchServiceClient`
    :param str job_id: The ID of the job to which to add the tasks.
    :param list input_files: A collection of input files. One task will be
     created for each input file.
    :param output_container_name: The ID of an Azure Blob storage container to
    which the tasks will upload their results.
    :param output_container_sas_token: A SAS token granting write access to
    the specified Azure Blob storage container.
    """

    print('Adding {} tasks to job [{}]...'.format(len(input_files), job_id))

    tasks = list()

    for input_file in input_files:

        command = ['python $AZ_BATCH_NODE_SHARED_DIR/python_tutorial_task.py '
                   '--filepath {} --numwords {} --storageaccount {} '
                   '--storagecontainer {} --sastoken "{}"'.format(
                    input_file.file_path,
                    '3',
                    _STORAGE_ACCOUNT_NAME,
                    output_container_name,
                    output_container_sas_token)]

        tasks.append(batch.models.TaskAddParameter(
                'topNtask{}'.format(input_files.index(input_file)),
                wrap_commands_in_shell('linux', command),
                resource_files=[input_file]
                )
        )

    batch_service_client.task.add_collection(job_id, tasks)

Importante

Quando accedono a variabili di ambiente come $AZ_BATCH_NODE_SHARED_DIR o eseguono un'applicazione non presente nell'elemento PATH del nodo, le righe di comando delle attività devono richiamare la shell in modo esplicito, ad esempio con /bin/sh -c MyTaskApplication $MY_ENV_VAR.When they access environment variables such as $AZ_BATCH_NODE_SHARED_DIR or execute an application not found in the node's PATH, task command lines must invoke the shell explicitly, such as with /bin/sh -c MyTaskApplication $MY_ENV_VAR. Questo requisito è superfluo se le attività eseguono un'applicazione nell'elemento PATH del nodo e non fanno riferimento a variabili di ambiente.This requirement is unnecessary if your tasks execute an application in the node's PATH and do not reference any environment variables.

Nel ciclo for del frammento di codice precedente, la riga di comando per l'attività è costruita con cinque argomenti della riga di comando che vengono passati a python_tutorial_task.py:Within the for loop in the code snippet above, you can see that the command line for the task is constructed with five command-line arguments that are passed to python_tutorial_task.py:

  1. filepath: percorso locale del file esistente nel nodo.filepath: This is the local path to the file as it exists on the node. Durante la creazione dell'oggetto ResourceFile in upload_file_to_container nel precedente passaggio 2, per questa proprietà (parametro file_path nel costruttore ResourceFile) è stato usato il nome file.When the ResourceFile object in upload_file_to_container was created in Step 2 above, the file name was used for this property (the file_path parameter in the ResourceFile constructor). Ciò indica che il file si trova nella stessa directory di python_tutorial_task.py nel nodo.This indicates that the file can be found in the same directory on the node as python_tutorial_task.py.
  2. numwords: le prime N parole devono essere scritte nel file di output.numwords: The top N words should be written to the output file.
  3. storageaccount: nome dell'account di archiviazione proprietario del contenitore in cui dovrà essere caricato l'output dell'attività.storageaccount: The name of the Storage account that owns the container to which the task output should be uploaded.
  4. storagecontainer: nome del contenitore di archiviazione in cui dovranno essere caricati i file di output.storagecontainer: The name of the Storage container to which the output files should be uploaded.
  5. sastoken: firma di accesso condiviso che consente l'accesso in scrittura al contenitore output in Archiviazione di Azure.sastoken: The shared access signature (SAS) that provides write access to the output container in Azure Storage. Lo script python_tutorial_task.py usa questa firma di accesso condiviso quando crea il riferimento BlockBlobService.The python_tutorial_task.py script uses this shared access signature when creates its BlockBlobService reference. È così possibile accedere al contenitore in scrittura senza una chiave di accesso dell'account di archiviazione.This provides write access to the container without requiring an access key for the storage account.
# NOTE: Taken from python_tutorial_task.py

# Create the blob client using the container's SAS token.
# This allows us to create a client that provides write
# access only to the container.
blob_client = azureblob.BlockBlobService(account_name=args.storageaccount,
                                         sas_token=args.sastoken)

Passaggio 6: Monitorare le attivitàStep 6: Monitor tasks

Monitorare le attivitàMonitor tasks
(1) Lo script monitora le attività per verificare lo stato di completamento e (2) le attività caricano i dati dei risultati in Archiviazione di Azure The script (1) monitors the tasks for completion status, and (2) the tasks upload result data to Azure Storage

Quando le attività vengono aggiunte a un processo, vengono accodate automaticamente e ne viene pianificata l'esecuzione nei nodi di calcolo entro il pool associato al progetto.When tasks are added to a job, they are automatically queued and scheduled for execution on compute nodes within the pool associated with the job. In base alle impostazioni specificate, Batch gestisce tutte le operazioni di accodamento, pianificazione, ripetizione di tentativi dell'attività e tutte le altre operazioni amministrative relative all'attività.Based on the settings you specify, Batch handles all task queuing, scheduling, retrying, and other task administration duties for you.

Sono disponibili molti approcci al monitoraggio dell'esecuzione delle attività.There are many approaches to monitoring task execution. La funzione wait_for_tasks_to_complete in python_tutorial_client.py offre un esempio semplice di monitoraggio delle attività per un determinato stato, in questo caso lo stato Completed.The wait_for_tasks_to_complete function in python_tutorial_client.py provides a simple example of monitoring tasks for a certain state, in this case, the completed state.

def wait_for_tasks_to_complete(batch_service_client, job_id, timeout):
    """
    Returns when all tasks in the specified job reach the Completed state.

    :param batch_service_client: A Batch service client.
    :type batch_service_client: `azure.batch.BatchServiceClient`
    :param str job_id: The id of the job whose tasks should be to monitored.
    :param timedelta timeout: The duration to wait for task completion. If all
    tasks in the specified job do not reach Completed state within this time
    period, an exception will be raised.
    """
    timeout_expiration = datetime.datetime.now() + timeout

    print("Monitoring all tasks for 'Completed' state, timeout in {}..."
          .format(timeout), end='')

    while datetime.datetime.now() < timeout_expiration:
        print('.', end='')
        sys.stdout.flush()
        tasks = batch_service_client.task.list(job_id)

        incomplete_tasks = [task for task in tasks if
                            task.state != batchmodels.TaskState.completed]
        if not incomplete_tasks:
            print()
            return True
        else:
            time.sleep(1)

    print()
    raise RuntimeError("ERROR: Tasks did not reach 'Completed' state within "
                       "timeout period of " + str(timeout))

Passaggio 7: Scaricare l'output dell'attivitàStep 7: Download task output

Scaricare l'output delle attività dal servizio di archiviazioneDownload task output from Storage

Dopo il completamento del processo, l'output delle attività può essere scaricato da Archiviazione di AzureNow that the job is completed, the output from the tasks can be downloaded from Azure Storage. con una chiamata a download_blobs_from_container in python_tutorial_client.py:This is done with a call to download_blobs_from_container in python_tutorial_client.py:

def download_blobs_from_container(block_blob_client,
                                  container_name, directory_path):
    """
    Downloads all blobs from the specified Azure Blob storage container.

    :param block_blob_client: A blob service client.
    :type block_blob_client: `azure.storage.blob.BlockBlobService`
    :param container_name: The Azure Blob storage container from which to
     download files.
    :param directory_path: The local directory to which to download the files.
    """
    print('Downloading all files from container [{}]...'.format(
        container_name))

    container_blobs = block_blob_client.list_blobs(container_name)

    for blob in container_blobs.items:
        destination_file_path = os.path.join(directory_path, blob.name)

        block_blob_client.get_blob_to_path(container_name,
                                           blob.name,
                                           destination_file_path)

        print('  Downloaded blob [{}] from container [{}] to {}'.format(
            blob.name,
            container_name,
            destination_file_path))

    print('  Download complete!')

Nota

La chiamata a download_blobs_from_container in python_tutorial_client.py specifica che i file devono essere scaricati nella home directory dell'utente.The call to download_blobs_from_container in python_tutorial_client.py specifies that the files should be downloaded to your home directory. È possibile modificare questo percorso di output.Feel free to modify this output location.

Passaggio 8: Eliminare i contenitoriStep 8: Delete containers

Poiché vengono effettuati addebiti per i dati che risiedono in Archiviazione di Azure, è consigliabile rimuovere eventuali BLOB non più necessari per i processi di Batch.Because you are charged for data that resides in Azure Storage, it is always a good idea to remove any blobs that are no longer needed for your Batch jobs. In python_tutorial_client.py, questa operazione viene eseguita con tre chiamate a BlockBlobService.delete_container:In python_tutorial_client.py, this is done with three calls to BlockBlobService.delete_container:

# Clean up storage resources
print('Deleting containers...')
blob_client.delete_container(app_container_name)
blob_client.delete_container(input_container_name)
blob_client.delete_container(output_container_name)

Passaggio 9: Eliminare il processo e il poolStep 9: Delete the job and the pool

Nel passaggio finale viene richiesto all'utente di eliminare il processo e il pool creati dallo script python_tutorial_client.py.In the final step, you are prompted to delete the job and the pool that were created by the python_tutorial_client.py script. Anche se non vengono addebitati costi per i processi e le attività in sé, vengono addebiti costi per i nodi di calcolo.Although you are not charged for jobs and tasks themselves, you are charged for compute nodes. È quindi consigliabile allocare i nodi solo in base alla necessità.Thus, we recommend that you allocate nodes only as needed. L'eliminazione dei pool inutilizzati può fare parte del processo di manutenzione.Deleting unused pools can be part of your maintenance process.

Gli elementi JobOperations e PoolOperations di BatchServiceClient includono metodi di eliminazione corrispondenti, che vengono chiamati se l'utente conferma l'eliminazione:The BatchServiceClient's JobOperations and PoolOperations both have corresponding deletion methods, which are called if you confirm deletion:

# Clean up Batch resources (if the user so chooses).
if query_yes_no('Delete job?') == 'yes':
    batch_client.job.delete(_JOB_ID)

if query_yes_no('Delete pool?') == 'yes':
    batch_client.pool.delete(_POOL_ID)

Importante

Occorre ricordare che vengono effettuati addebiti per le risorse di calcolo e che l'eliminazione di pool inutilizzati consente di ridurre al minimo i costi.Keep in mind that you are charged for compute resources--deleting unused pools will minimize cost. Si noti anche che l'eliminazione di un pool comporta l'eliminazione di tutti i nodi di calcolo in quel pool e che eventuali dati disponibili nei nodi non potranno essere più recuperati dopo l'eliminazione del pool.Also, be aware that deleting a pool deletes all compute nodes within that pool, and that any data on the nodes will be unrecoverable after the pool is deleted.

Eseguire lo script di esempioRun the sample script

Quando si esegue lo script python_tutorial_client.py dal codice di esempio dell'esercitazione, l'output della console sarà simile al seguente.When you run the python_tutorial_client.py script from the tutorial code sample, the console output is similar to the following. Si riscontra una pausa in corrispondenza di Monitoring all tasks for 'Completed' state, timeout in 0:20:00... mentre vengono creati e avviati i nodi di calcolo del pool e vengono eseguiti i comandi nell'attività iniziale del pool.There is a pause at Monitoring all tasks for 'Completed' state, timeout in 0:20:00... while the pool's compute nodes are created, started, and the commands in the pool's start task are executed. Usare il portale di Azure per monitorare il pool, i nodi di calcolo, il processo e le attività durante e dopo l'esecuzione.Use the Azure portal to monitor your pool, compute nodes, job, and tasks during and after execution. Usare il portale di Azure o Microsoft Azure Storage Explorer per visualizzare le risorse di archiviazione (contenitori e BLOB) create dall'applicazione.Use the Azure portal or the Microsoft Azure Storage Explorer to view the Storage resources (containers and blobs) that are created by the application.

Suggerimento

Eseguire lo script python_tutorial_client.py dalla directory azure-batch-samples/Python/Batch/article_samples.Run the python_tutorial_client.py script from within the azure-batch-samples/Python/Batch/article_samples directory. che usa un percorso relativo per l'importazione del modulo common.helpers. Perciò se non si esegue lo script da questa directory, è possibile che venga visualizzato il messaggio ImportError: No module named 'common'.It uses a relative path for the common.helpers module import, so you might see ImportError: No module named 'common' if you don't run the script from within this directory.

Se si esegue l'esempio con la configurazione predefinita, il tempo di esecuzione tipico è di circa 5-7 minuti .Typical execution time is approximately 5-7 minutes when you run the sample in its default configuration.

Sample start: 2016-05-20 22:47:10

Uploading file /home/user/py_tutorial/python_tutorial_task.py to container [application]...
Uploading file /home/user/py_tutorial/data/taskdata1.txt to container [input]...
Uploading file /home/user/py_tutorial/data/taskdata2.txt to container [input]...
Uploading file /home/user/py_tutorial/data/taskdata3.txt to container [input]...
Creating pool [PythonTutorialPool]...
Creating job [PythonTutorialJob]...
Adding 3 tasks to job [PythonTutorialJob]...
Monitoring all tasks for 'Completed' state, timeout in 0:20:00..........................................................................
  Success! All tasks reached the 'Completed' state within the specified timeout period.
Downloading all files from container [output]...
  Downloaded blob [taskdata1_OUTPUT.txt] from container [output] to /home/user/taskdata1_OUTPUT.txt
  Downloaded blob [taskdata2_OUTPUT.txt] from container [output] to /home/user/taskdata2_OUTPUT.txt
  Downloaded blob [taskdata3_OUTPUT.txt] from container [output] to /home/user/taskdata3_OUTPUT.txt
  Download complete!
Deleting containers...

Sample end: 2016-05-20 22:53:12
Elapsed time: 0:06:02

Delete job? [Y/n]
Delete pool? [Y/n]

Press ENTER to exit...

Passaggi successiviNext steps

È possibile modificare python_tutorial_client.py e python_tutorial_task.py per sperimentare scenari di calcolo diversi.Feel free to make changes to python_tutorial_client.py and python_tutorial_task.py to experiment with different compute scenarios. Si può ad esempio provare ad aggiungere un ritardo di esecuzione in python_tutorial_task.py per simulare attività con esecuzione prolungata e monitorarle nel portale.For example, try adding an execution delay to python_tutorial_task.py to simulate long-running tasks and monitor them in the portal. Provare ad aggiungere altre attività o a modificare il numero di nodi di calcolo.Try adding more tasks or adjusting the number of compute nodes. Aggiungere la logica per la ricerca e l'uso di un pool esistente per ridurre il tempo di esecuzione.Add logic to check for and allow the use of an existing pool to speed execution time.

Dopo avere acquisito familiarità con il flusso di lavoro di base di una soluzione Batch, è possibile esaminare in dettaglio le funzionalità aggiuntive del servizio Batch.Now that you're familiar with the basic workflow of a Batch solution, it's time to dig in to the additional features of the Batch service.