Exécuter des jobs dans une session
Versions des packages
Le code de cette page a été développé avec les dépendances suivantes. Nous recommandons d'utiliser ces versions ou des versions plus récentes.
qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
scipy~=1.16.3
Les utilisateurs du plan Open ne peuvent pas soumettre de jobs en session. Les charges de travail doivent être exécutées en mode job ou en mode batch.
Utilise les sessions lorsque tu as besoin d'un accès dédié et exclusif au QPU.
Configurer l'utilisation des sessions
Avant de démarrer une session, tu dois configurer Qiskit Runtime et l'initialiser en tant que service :
# Added by doQumentation — required packages for this notebook
!pip install -q numpy qiskit qiskit-ibm-runtime scipy
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Session,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
service = QiskitRuntimeService()
Ouvrir une session
Tu peux ouvrir une session runtime en utilisant le gestionnaire de contexte with Session(...) ou en instanciant la classe Session.
Lorsque tu démarres une session, tu dois spécifier un QPU en passant un objet backend. La session démarre quand son premier job commence à s'exécuter.
Si tu ouvres une session sans y soumettre de jobs pendant 30 minutes, la session se ferme automatiquement.
Classe Session
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
backend = service.least_busy(operational=True, simulator=False)
session = Session(backend=backend)
estimator = Estimator(mode=session)
sampler = Sampler(mode=session)
# Close the session because no context manager was used.
session.close()
Gestionnaire de contexte
Le gestionnaire de contexte ouvre et ferme automatiquement la session.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
from qiskit_ibm_runtime import (
Session,
SamplerV2 as Sampler,
EstimatorV2 as Estimator,
)
backend = service.least_busy(operational=True, simulator=False)
with Session(backend=backend):
estimator = Estimator()
sampler = Sampler()
Durée d'une session
La durée de vie maximale d'une session (TTL) détermine combien de temps elle peut s'exécuter. Tu peux définir cette valeur avec le paramètre max_time. Elle doit dépasser le temps d'exécution du job le plus long.
Ce minuteur démarre au lancement de la session. Lorsque la valeur est atteinte, la session est fermée. Les jobs en cours d'exécution se terminent, mais les jobs encore en file d'attente échouent.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
with Session(backend=backend, max_time="25m"):
...
Il existe également une valeur de durée de vie interactive (TTL interactif) qui ne peut pas être configurée. Si aucun job de session n'est mis en file d'attente dans cette fenêtre, la session est temporairement désactivée.
Valeurs par défaut :
| Type d'instance (plan Open ou Premium) | TTL interactif | TTL maximum |
|---|---|---|
| Plan Premium | 60 sec* | 8 h* |
| * Certaines instances du plan Premium peuvent être configurées avec une valeur différente. |
Pour déterminer le TTL maximum ou le TTL interactif d'une session, suis les instructions de la section Consulter les détails d'une session et cherche respectivement les valeurs max_time ou interactive_timeout.
Terminer une session
Une session se termine dans les circonstances suivantes :
- La valeur maximale du délai d'expiration (TTL) est atteinte, entraînant l'annulation de tous les jobs en file d'attente.
- La session est annulée manuellement, entraînant l'annulation de tous les jobs en file d'attente.
- La session est fermée manuellement. Elle cesse d'accepter de nouveaux jobs mais continue à exécuter les jobs en file d'attente en priorité.
- Si tu utilises Session comme gestionnaire de contexte, c'est-à-dire
with Session(), la session se ferme automatiquement à la fin du contexte (comportement identique àsession.close()).
Fermer une session
Une session se ferme automatiquement lorsqu'elle quitte le gestionnaire de contexte. À ce moment, elle passe au statut « En cours, n'accepte plus de nouveaux jobs ». Cela signifie qu'elle termine tous les jobs en cours d'exécution ou en file d'attente jusqu'à ce que la valeur maximale du délai d'expiration soit atteinte. Une fois tous les jobs terminés, la session est immédiatement fermée. Cela permet au planificateur d'exécuter le job suivant sans attendre le délai d'expiration interactif de la session, réduisant ainsi le temps moyen d'attente des jobs. Tu ne peux pas soumettre de jobs à une session fermée.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
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()
# Create parameters and mapped observables to submit
params = np.random.uniform(size=(2, 3)).T
observables = [
SparsePauliOp(["XX", "IY"], [0.5, 0.5]),
SparsePauliOp("XX"),
SparsePauliOp("IY"),
]
mapped_observables = [
[observable.apply_layout(transpiled_circuit.layout)]
for observable in observables
]
sampler_pub = (transpiled_circuit_sampler, params)
estimator_pub = (transpiled_circuit_sampler, mapped_observables, params)
with Session(backend=backend) as session:
estimator = Estimator()
sampler = Sampler()
job1 = estimator.run([estimator_pub])
job2 = sampler.run([sampler_pub])
# The session is no longer accepting jobs but the submitted job will run to completion.
result = job1.result()
result2 = job2.result()
Si tu n'utilises pas de gestionnaire de contexte, ferme manuellement la session pour éviter des coûts inattendus. Tu peux fermer une session dès que tu as fini de lui soumettre des jobs. Lorsqu'une session est fermée avec session.close(), elle n'accepte plus de nouveaux jobs, mais les jobs déjà soumis continueront à s'exécuter jusqu'à leur terme et leurs résultats pourront être récupérés.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
session = Session(backend=backend)
# If using qiskit-ibm-runtime earlier than 0.24.0, change `mode=` to `session=`
estimator = Estimator(mode=session)
sampler = Sampler(mode=session)
job1 = estimator.run([estimator_pub])
job2 = sampler.run([sampler_pub])
print(f"Result1: {job1.result()}")
print(f"Result2: {job2.result()}")
# Manually close the session. Running and queued jobs will run to completion.
session.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:53:15', stop='2026-01-15 07:53:21', size=24576>)])}, 'version': 2})
Vérifier le statut d'une session
Tu peux interroger le statut d'une session pour comprendre son état actuel en utilisant session.status() ou en consultant la page Workloads.
Le statut d'une session peut être l'un des suivants :
Pending: La session n'a pas encore démarré ou a été désactivée. Le prochain job de session doit attendre dans la file d'attente comme les autres jobs.In progress, accepting new jobs: La session est active et accepte de nouveaux jobs.In progress, not accepting new jobs: La session est active mais n'accepte plus de nouveaux jobs. La soumission de jobs à la session est refusée, mais les jobs de session en cours seront exécutés jusqu'à leur terme. La session se ferme automatiquement une fois tous les jobs terminés.Closed: La valeur maximale du délai d'expiration de la session a été atteinte ou la session a été explicitement fermée.
Consulter les détails d'une session
Pour obtenir une vue d'ensemble complète de la configuration et du statut d'une session, utilise la méthode session.details().
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
from qiskit_ibm_runtime import (
QiskitRuntimeService,
Session,
EstimatorV2 as Estimator,
)
service = QiskitRuntimeService()
backend = service.least_busy(operational=True, simulator=False)
with Session(backend=backend) as session:
print(session.details())
{'id': 'be84569d-86b5-4a7f-be5e-7d33e80dc220', 'backend_name': 'ibm_torino', 'interactive_timeout': 60, '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': 'dedicated', 'usage_time': None}
Modèles d'utilisation
Les sessions sont particulièrement utiles pour les algorithmes nécessitant des échanges fréquents entre des ressources classiques et quantiques.
Exemple : exécute une charge de travail itérative qui utilise l'optimiseur classique SciPy pour minimiser une fonction de coût. Dans ce modèle, SciPy utilise la sortie de la fonction de coût pour calculer son prochain paramètre d'entrée.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
from scipy.optimize import minimize
from qiskit.circuit.library import efficient_su2
def cost_func(params, ansatz, hamiltonian, estimator):
# Return estimate of energy from estimator
energy = sum(
estimator.run([(ansatz, hamiltonian, params)]).result()[0].data.evs
)
return energy
hamiltonian = SparsePauliOp.from_list(
[("YZ", 0.3980), ("ZI", -0.3980), ("ZZ", -0.0113), ("XX", 0.1810)]
)
su2_ansatz = efficient_su2(hamiltonian.num_qubits)
pm = generate_preset_pass_manager(backend=backend, optimization_level=3)
ansatz = pm.run(su2_ansatz)
mapped_hamiltonian = [
operator.apply_layout(ansatz.layout) for operator in hamiltonian
]
num_params = ansatz.num_parameters
x0 = 2 * np.pi * np.random.random(num_params)
session = Session(backend=backend)
# If using qiskit-ibm-runtime earlier than 0.24.0, change `mode=` to `session=`
estimator = Estimator(mode=session, options={"default_shots": int(1e4)})
res = minimize(
cost_func,
x0,
args=(ansatz, mapped_hamiltonian, estimator),
method="cobyla",
options={"maxiter": 25},
)
# Close the session because no context manager was used.
session.close()
Exécuter deux algorithmes VQE dans une session avec le threading
Tu peux tirer davantage parti d'une session en exécutant plusieurs charges de travail simultanément. L'exemple suivant montre comment exécuter deux algorithmes VQE, chacun utilisant un optimiseur classique différent, simultanément dans une seule session. Des étiquettes de job sont également utilisées pour différencier les jobs de chaque charge de travail.
Le bloc de code suivant retournera une erreur pour les utilisateurs du plan Open car il utilise des sessions. Les charges de travail du plan Open ne peuvent s'exécuter qu'en mode job ou en mode batch.
from concurrent.futures import ThreadPoolExecutor
from qiskit_ibm_runtime import EstimatorV2 as Estimator
def minimize_thread(estimator, method):
return minimize(
cost_func,
x0,
args=(ansatz, mapped_hamiltonian, estimator),
method=method,
options={"maxiter": 25},
)
with Session(backend=backend), ThreadPoolExecutor() as executor:
estimator1 = Estimator()
estimator2 = Estimator()
# Use different tags to differentiate the jobs.
estimator1.options.environment.job_tags = ["cobyla"]
estimator2.options.environment.job_tags = ["nelder-mead"]
# Submit the two workloads.
cobyla_future = executor.submit(minimize_thread, estimator1, "cobyla")
nelder_mead_future = executor.submit(
minimize_thread, estimator2, "nelder-mead"
)
# Get workload results.
cobyla_result = cobyla_future.result()
nelder_mead_result = nelder_mead_future.result()
Prochaines étapes
- Essaie un exemple dans le tutoriel Algorithme d'optimisation quantique approximative (QAOA).
- Consulte la référence de l'API Session.
- Comprends les limites de jobs lors de l'envoi d'un job à un QPU IBM®.
- Consulte la FAQ sur les modes d'exécution.