Aller au contenu principal
Ce projet est en phase bêta. Tu as trouvé un bug ? Ouvrir un ticket GitHub. Une question ou une idée ? Pose ta question dans Discussions — tes retours sont les bienvenus !
Quelle est la qualité de la traduction sur cette page ?

Exécuter des jobs en mode batch

Versions des paquets

Le code de cette page a été développé avec les versions suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.

qiskit[all]~=2.5.2
qiskit-ibm-runtime~=0.47.0

Utilise le batch mode pour soumettre plusieurs jobs de primitives simultanément. Voici des exemples de travail avec des batches.

Configurer l'utilisation des batches​

Avant de démarrer un batch, tu dois configurer le client IBM Quantum Compute et l'initialiser en tant que service :

# Added by doQumentation — installs the packages this notebook needs if they are missing
import importlib.util

_needed = {"numpy": "numpy", "qiskit": "qiskit", "qiskit_ibm_runtime": "qiskit-ibm-runtime"}
_missing = [pip for module, pip in _needed.items()
if importlib.util.find_spec(module) is None]
# One at a time, so a package that fails to install does not block the others
for _pip in _missing:
%pip install -q {_pip}
if not _missing:
print("\u2713 All required packages are installed")
from qiskit_ibm_runtime import QiskitRuntimeService, Batch, Executor

# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import Sampler, Estimator

# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import Estimator

service = QiskitRuntimeService()

Ouvrir un batch​

Tu peux ouvrir un batch Runtime en utilisant le gestionnaire de contexte with Batch(...) ou en instanciant la classe Batch. Lorsque tu démarres un batch, tu dois spécifier un QPU en passant un objet backend. Le batch démarre quand son premier job commence à s'exécuter.

Classe Batch

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

Gestionnaire de contexte

Le gestionnaire de contexte ouvre et ferme automatiquement le batch.

from qiskit_ibm_runtime import Batch, Executor

# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import Sampler, Estimator

# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler
from qiskit_ibm_runtime.executor_estimator import Estimator

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

Durée de vie d'un batch​

Tu peux définir la durée de vie maximale (TTL) d'un batch avec le paramètre max_time. Cette valeur doit dépasser le temps d'exécution du job le plus long. Ce minuteur démarre quand le batch commence. Lorsque la valeur est atteinte, le batch est fermé. Les jobs en cours d'exécution se terminent, mais les jobs encore en file d'attente échouent.

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

Il existe également une valeur de durée de vie interactive (TTL interactif) qui n'est pas configurable (1 minute pour tous les plans). Si aucun job de batch n'est mis en file d'attente dans cette fenêtre, le batch est temporairement désactivé.

Valeurs TTL maximales par défaut :

Type d'instanceTTL maximum par défaut
Tous les plans payants8 heures
Open10 minutes

Pour déterminer le TTL maximum ou le TTL interactif d'un batch, suis les instructions dans Déterminer les détails d'un batch et recherche les valeurs max_time ou interactive_timeout respectivement.

Fermer un batch​

Un batch se ferme automatiquement lorsqu'il sort du gestionnaire de contexte. Quand le gestionnaire de contexte du batch est quitté, le batch passe en état « En cours, n'acceptant plus de nouveaux jobs ». Cela signifie que le batch termine de traiter tous les jobs en cours d'exécution ou en file d'attente jusqu'à ce que la valeur TTL maximale soit atteinte. Une fois tous les jobs terminés, le batch est immédiatement fermé. Tu ne peux pas soumettre de jobs à un batch fermé.

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)
remarque

Le code suivant nécessite que tu fournisses tes propres informations, telles que les PUB Estimator et Sampler, et un Backend.

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()
conseil

Si tu n'utilises pas de gestionnaire de contexte, ferme le batch manuellement. Si tu laisses le batch ouvert et soumets d'autres jobs plus tard, il est possible que le TTL maximum soit atteint avant que les jobs suivants commencent à s'exécuter, ce qui provoquerait leur annulation. Tu peux fermer un batch dès que tu as terminé de soumettre des jobs. Lorsqu'un batch est fermé avec batch.close(), il n'accepte plus de nouveaux jobs, mais les jobs déjà soumis continueront de s'exécuter jusqu'à leur achèvement et leurs résultats pourront être récupérés.

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=156>), shape=(3, 2)), metadata={'circuit_metadata': {}})], metadata={'execution': {'execution_spans': ExecutionSpans([DoubleSliceSpan(<start='2026-09-01 07:46:49', stop='2026-09-01 07:46:56', size=24576>)])}, 'version': 2})

Déterminer les détails d'un batch​

Pour un aperçu complet de la configuration et du statut d'un batch, y compris son TTL interactif et maximum, utilise la méthode batch.details() method.

from qiskit_ibm_runtime import QiskitRuntimeService, Batch

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

with Batch(backend=backend) as batch:
print(batch.details())
{'id': '947aa097-9055-42d4-9e58-ad1c2cdd9d5a', 'backend_name': 'ibm_marrakesh', '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}

Reconfigurer les jobs pour un traitement parallèle​

Il existe plusieurs façons de reconfigurer tes jobs pour tirer parti du traitement parallèle offert par le batching. L'exemple suivant montre comment tu peux partitionner une longue liste de circuits en plusieurs jobs et les exécuter en batch pour bénéficier du traitement parallèle.

from qiskit.circuit.random import random_circuit
from qiskit_ibm_runtime import Batch

# Legacy server-side primitive before qiskit-ibm-runtime 0.50.0
# from qiskit_ibm_runtime import Sampler

# Client-side primitive introduced in qiskit-ibm-runtime 0.50.0
from qiskit_ibm_runtime.executor_sampler import Sampler

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)
attention

Si tu définis backend=backend dans une primitive, le programme s'exécute en job mode, même s'il se trouve à l'intérieur d'un contexte batch ou session. L'utilisation de backend=backend est obsolète depuis Qiskit Runtime v0.24.0. Utilise plutôt le paramètre mode.

Prochaines étapes​

Recommandations