Zum Hauptinhalt springen

Jobs im Batch-Modus ausführen

Paketversionen

Der Code auf dieser Seite wurde mit den folgenden Anforderungen entwickelt. Wir empfehlen die Verwendung dieser oder neuerer Versionen.

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

Verwende den Batch-Modus, um mehrere Primitive-Jobs gleichzeitig zu übermitteln. Im Folgenden findest du Beispiele für die Arbeit mit Batches.

Einrichtung für die Verwendung von Batches

Bevor du einen Batch startest, musst du Qiskit Runtime einrichten und es als Service initialisieren:

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

Einen Batch öffnen

Du kannst einen Runtime-Batch mithilfe des Context-Managers with Batch(...) oder durch Initialisierung der Klasse Batch öffnen. Wenn du einen Batch startest, musst du einen QPU angeben, indem du ein backend-Objekt übergibst. Der Batch startet, sobald sein erster Job mit der Ausführung beginnt.

Batch-Klasse

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

Der Context-Manager öffnet und schließt den Batch automatisch.

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

Batch-Laufzeit

Du kannst die maximale Lebensdauer (TTL) des Batches mit dem Parameter max_time festlegen. Dieser Wert sollte die Ausführungszeit des längsten Jobs überschreiten. Der Timer startet, wenn der Batch beginnt. Wird der Wert erreicht, wird der Batch geschlossen. Alle laufenden Jobs werden abgeschlossen, aber noch in der Warteschlange befindliche Jobs schlagen fehl.

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

Es gibt auch einen interaktiven Time-to-Live-Wert (interaktive TTL), der nicht konfiguriert werden kann (1 Minute für alle Pläne). Wenn innerhalb dieses Zeitfensters keine Batch-Jobs in die Warteschlange gestellt werden, wird der Batch vorübergehend deaktiviert.

Standardmäßige maximale TTL-Werte:

InstanztypStandardmäßige maximale TTL
Alle kostenpflichtigen Pläne8 Stunden
Open10 Minuten

Um die maximale TTL oder die interaktive TTL eines Batches zu ermitteln, folge den Anweisungen unter Batch-Details abrufen und suche nach dem Wert max_time bzw. interactive_timeout.

Einen Batch schließen

Ein Batch schließt automatisch, wenn er den Context-Manager verlässt. Wenn der Batch-Context-Manager beendet wird, wechselt der Batch in den Status „In Bearbeitung, keine neuen Jobs werden akzeptiert". Das bedeutet, dass der Batch alle laufenden oder in der Warteschlange befindlichen Jobs abarbeitet, bis der maximale TTL-Wert erreicht wird. Nachdem alle Jobs abgeschlossen sind, wird der Batch sofort geschlossen. Du kannst keine Jobs an einen geschlossenen Batch übermitteln.

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

Wenn du keinen Context-Manager verwendest, schließe den Batch manuell. Wenn du den Batch offen lässt und später weitere Jobs daran übermittelst, kann es vorkommen, dass die maximale TTL erreicht wird, bevor die nachfolgenden Jobs mit der Ausführung beginnen, was dazu führt, dass sie abgebrochen werden. Du kannst einen Batch schließen, sobald du mit der Übermittlung von Jobs fertig bist. Wenn ein Batch mit batch.close() geschlossen wird, akzeptiert er keine neuen Jobs mehr, aber die bereits übermittelten Jobs werden bis zum Abschluss ausgeführt und ihre Ergebnisse können abgerufen werden.

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

Batch-Details abrufen

Für einen umfassenden Überblick über die Konfiguration und den Status eines Batches, einschließlich seiner interaktiven und maximalen TTL, verwende die Methode 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}

Jobs für die parallele Verarbeitung neu konfigurieren

Es gibt mehrere Möglichkeiten, deine Jobs neu zu konfigurieren, um die durch Batching bereitgestellte parallele Verarbeitung zu nutzen. Das folgende Beispiel zeigt, wie du eine lange Liste von Circuits in mehrere Jobs aufteilen und als Batch ausführen kannst, um die parallele Verarbeitung zu nutzen.

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

Wenn du backend=backend in einem Primitiv setzt, wird das Programm im Job-Modus ausgeführt, auch wenn es sich innerhalb eines Batch- oder Session-Kontexts befindet. Das Setzen von backend=backend ist seit Qiskit Runtime v0.24.0 veraltet. Verwende stattdessen den Parameter mode.

Nächste Schritte

Empfehlungen