Vai al contenuto principale

Eseguire job in batch

Versioni dei pacchetti

Il codice in questa pagina è stato sviluppato con i seguenti requisiti. Si consiglia di usare queste versioni o versioni più recenti.

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1

Usa la modalità batch per inviare più job primitivi contemporaneamente. Di seguito trovi esempi di utilizzo dei batch.

Configurazione per l'uso dei batch

Prima di avviare un batch, devi configurare Qiskit Runtime e inizializzarlo come servizio:

# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)

service = QiskitRuntimeService()

Aprire un batch

Puoi aprire un batch di runtime usando il context manager with Batch(...) oppure inizializzando direttamente la classe Batch. Quando avvii un batch, devi specificare una QPU passando un oggetto backend. Il batch ha inizio quando viene eseguito il primo job.

Classe Batch

backend = service.least_busy(operational=True, simulator=False)
batch = Batch(backend=backend)
estimator = Estimator(mode=batch)
sampler = Sampler(mode=batch)
# Close the batch because no context manager was used.
batch.close()

Context manager

Il context manager apre e chiude il batch automaticamente.

from qiskit_ibm_runtime import (
Batch,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)

backend = service.least_busy(operational=True, simulator=False)
with Batch(backend=backend):
estimator = Estimator()
sampler = Sampler()

Durata del batch

Puoi definire il tempo di vita massimo (TTL) del batch tramite il parametro max_time. Questo valore dovrebbe superare il tempo di esecuzione del job più lungo. Il timer parte quando il batch viene avviato. Al raggiungimento del valore impostato, il batch viene chiuso. I job in esecuzione verranno completati, ma quelli ancora in coda verranno marcati come falliti.

with Batch(backend=backend, max_time="25m"):
...

Esiste anche un valore di tempo di vita interattivo (interactive TTL) che non è configurabile (1 minuto per tutti i piani). Se nessun job del batch viene messo in coda entro questa finestra temporale, il batch viene temporaneamente disattivato.

Valori TTL massimi predefiniti:

Tipo di istanzaTTL massimo predefinito
Tutti i piani a pagamento8 ore
Open10 minuti

Per determinare il TTL massimo o il TTL interattivo di un batch, segui le istruzioni in Determinare i dettagli del batch e cerca i valori max_time o interactive_timeout, rispettivamente.

Chiudere un batch

Un batch si chiude automaticamente quando si esce dal context manager. Quando il context manager del batch viene abbandonato, il batch passa allo stato "In corso, non accetta nuovi job". Questo significa che il batch termina l'elaborazione di tutti i job in esecuzione o in coda fino al raggiungimento del valore TTL massimo. Una volta completati tutti i job, il batch viene chiuso immediatamente. Non è possibile inviare job a un batch chiuso.

from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.transpiler import generate_preset_pass_manager
import numpy as np

# This cell is hidden from users
service = QiskitRuntimeService()
backend = service.least_busy()

# Define two circuits, each with one parameter with two parameters.
circuit = QuantumCircuit(2)
circuit.h(0)
circuit.cx(0, 1)
circuit.ry(Parameter("a"), 0)
circuit.cx(0, 1)
circuit.h(0)
circuit.measure_all()

pm = generate_preset_pass_manager(optimization_level=1, backend=backend)
transpiled_circuit = pm.run(circuit)
transpiled_circuit_sampler = transpiled_circuit
transpiled_circuit_sampler.measure_all()

params = np.random.uniform(size=(2, 3)).T
observables = [
[
SparsePauliOp(["XX", "IY"], [0.5, 0.5]).apply_layout(
transpiled_circuit.layout
)
],
[SparsePauliOp("XX").apply_layout(transpiled_circuit.layout)],
[SparsePauliOp("IY").apply_layout(transpiled_circuit.layout)],
]

sampler_pub = (transpiled_circuit_sampler, params)
estimator_pub = (transpiled_circuit_sampler, observables, params)
with Batch(backend=backend) as batch:
estimator = Estimator()
sampler = Sampler()
job1 = estimator.run([estimator_pub])
job2 = sampler.run([sampler_pub])

# The batch is no longer accepting jobs but the submitted job will run to completion.
result = job1.result()
result2 = job2.result()
suggerimento

Se non stai usando un context manager, chiudi il batch manualmente. Se lasci il batch aperto e invii altri job in seguito, è possibile che il TTL massimo venga raggiunto prima che i job successivi inizino l'esecuzione, causandone la cancellazione. Puoi chiudere un batch non appena hai terminato di inviare job. Quando un batch viene chiuso con batch.close(), non accetta più nuovi job, ma quelli già inviati verranno comunque eseguiti fino al completamento e i loro risultati potranno essere recuperati.

batch = Batch(backend=backend)

# If using qiskit-ibm-runtime earlier than 0.24.0, change `mode=` to `batch=`
estimator = Estimator(mode=batch)
sampler = Sampler(mode=batch)
job1 = estimator.run([estimator_pub])
job2 = sampler.run([sampler_pub])
print(f"Result1: {job1.result()}")
print(f"Result2: {job2.result()}")

# Manually close the batch. Running and queued jobs will run to completion.
batch.close()
Result1: PrimitiveResult([PubResult(data=DataBin(evs=np.ndarray(<shape=(3, 2), dtype=float64>), stds=np.ndarray(<shape=(3, 2), dtype=float64>), ensemble_standard_error=np.ndarray(<shape=(3, 2), dtype=float64>), shape=(3, 2)), metadata={'shots': 4096, 'target_precision': 0.015625, 'circuit_metadata': {}, 'resilience': {}, 'num_randomizations': 32})], metadata={'dynamical_decoupling': {'enable': False, 'sequence_type': 'XX', 'extra_slack_distribution': 'middle', 'scheduling_method': 'alap'}, 'twirling': {'enable_gates': False, 'enable_measure': True, 'num_randomizations': 'auto', 'shots_per_randomization': 'auto', 'interleave_randomizations': True, 'strategy': 'active-accum'}, 'resilience': {'measure_mitigation': True, 'zne_mitigation': False, 'pec_mitigation': False}, 'version': 2})
Result2: PrimitiveResult([SamplerPubResult(data=DataBin(meas=BitArray(<shape=(3, 2), num_shots=4096, num_bits=2>), meas0=BitArray(<shape=(3, 2), num_shots=4096, num_bits=133>), shape=(3, 2)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-01-15 07:47:58', stop='2026-01-15 07:48:05', size=24576>)])}, 'version': 2})

Determinare i dettagli del batch

Per una panoramica completa della configurazione e dello stato di un batch, inclusi il TTL interattivo e il TTL massimo, usa il metodo batch.details().

from qiskit_ibm_runtime import (
QiskitRuntimeService,
batch,
SamplerV2 as Sampler,
)

service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)

with Batch(backend=backend) as batch:
print(batch.details())
{'id': 'ce8cf08d-b18e-4d56-ab51-eaff0b8190f4', 'backend_name': 'ibm_torino', 'interactive_timeout': 1, 'max_time': 28800, 'active_timeout': 28800, 'state': 'open', 'accepting_jobs': True, 'last_job_started': None, 'last_job_completed': None, 'started_at': None, 'closed_at': None, 'activated_at': None, 'mode': 'batch', 'usage_time': None}

Riconfigurare i job per l'elaborazione parallela

Esistono diversi modi per riconfigurare i tuoi job e sfruttare l'elaborazione parallela offerta dal batching. L'esempio seguente mostra come puoi suddividere un lungo elenco di circuiti in più job ed eseguirli come batch per sfruttare l'elaborazione parallela.

from qiskit_ibm_runtime import SamplerV2 as Sampler, Batch
from qiskit.circuit.random import random_circuit

max_circuits = 100
circuits = [pm.run(random_circuit(5, 5)) for _ in range(5 * max_circuits)]
for circuit in circuits:
circuit.measure_active()
all_partitioned_circuits = []
for i in range(0, len(circuits), max_circuits):
all_partitioned_circuits.append(circuits[i : i + max_circuits])
jobs = []
start_idx = 0

with Batch(backend=backend):
sampler = Sampler()
for partitioned_circuits in all_partitioned_circuits:
job = sampler.run(partitioned_circuits)
jobs.append(job)
attenzione

Se imposti backend=backend in un primitivo, il programma viene eseguito in modalità job, anche se si trova all'interno di un contesto batch o session. L'impostazione di backend=backend è deprecata a partire da Qiskit Runtime v0.24.0. Usa invece il parametro mode.

Passi successivi

Raccomandazioni