Saltar al contenido principal

Ejecutar trabajos en un lote

Versiones de paquetes

El código de esta página fue desarrollado con los siguientes requisitos. Te recomendamos usar estas versiones o versiones más recientes.

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

Usa el modo lote para enviar múltiples trabajos primitivos de forma simultánea. A continuación encontrarás ejemplos de cómo trabajar con lotes.

Configuración para usar lotes

Antes de iniciar un lote, debes configurar Qiskit Runtime e inicializarlo como servicio:

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

Abrir un lote

Puedes abrir un lote de runtime usando el gestor de contexto with Batch(...) o inicializando la clase Batch. Cuando inicias un lote, debes especificar una QPU pasando un objeto backend. El lote comienza cuando su primer trabajo empieza a ejecutarse.

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

Gestor de contexto

El gestor de contexto abre y cierra el lote automáticamente.

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

Duración del lote

Puedes definir el tiempo máximo de vida (TTL) del lote con el parámetro max_time. Este valor debe superar el tiempo de ejecución del trabajo más largo. El temporizador comienza cuando el lote se inicia. Cuando se alcanza el valor, el lote se cierra. Los trabajos que estén en ejecución terminarán, pero los que aún estén en cola fallarán.

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

También existe un valor de tiempo de vida interactivo (TTL interactivo) que no puede configurarse (1 minuto para todos los planes). Si no se ponen en cola trabajos del lote dentro de ese período, el lote se desactiva temporalmente.

Valores máximos de TTL predeterminados:

Tipo de instanciaTTL máximo predeterminado
Todos los planes de pago8 horas
Open10 minutos

Para determinar el TTL máximo o el TTL interactivo de un lote, sigue las instrucciones en Determinar los detalles del lote y busca el valor max_time o interactive_timeout, respectivamente.

Cerrar un lote

Un lote se cierra automáticamente cuando sale del gestor de contexto. Al salir del gestor de contexto del lote, este pasa al estado "En progreso, sin aceptar nuevos trabajos". Esto significa que el lote termina de procesar todos los trabajos en ejecución o en cola hasta que se alcanza el valor máximo de TTL. Una vez que todos los trabajos se completan, el lote se cierra de inmediato. No puedes enviar trabajos a un lote cerrado.

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

Si no estás usando un gestor de contexto, cierra el lote manualmente. Si dejas el lote abierto y envías más trabajos después, es posible que el TTL máximo se alcance antes de que los trabajos posteriores comiencen a ejecutarse, lo que causaría su cancelación. Puedes cerrar un lote en cuanto hayas terminado de enviar trabajos. Cuando un lote se cierra con batch.close(), ya no acepta nuevos trabajos, pero los trabajos ya enviados seguirán ejecutándose hasta completarse y sus resultados podrán recuperarse.

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

Determinar los detalles del lote

Para obtener una visión completa de la configuración y el estado de un lote, incluidos su TTL interactivo y máximo, usa el método 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}

Reconfigurar trabajos para procesamiento paralelo

Hay varias formas de reconfigurar tus trabajos para aprovechar el procesamiento paralelo que ofrece el modo lote. El siguiente ejemplo muestra cómo puedes dividir una lista larga de circuitos en múltiples trabajos y ejecutarlos como un lote para aprovechar el procesamiento paralelo.

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)
precaución

Si estableces backend=backend en una primitiva, el programa se ejecuta en modo trabajo, incluso si está dentro de un contexto de lote o sesión. El uso de backend=backend está en desuso a partir de Qiskit Runtime v0.24.0. En su lugar, usa el parámetro mode.

Próximos pasos

Recomendaciones