Vai al contenuto principale

Eseguire job in una sessione

Versioni dei pacchetti

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

qiskit[all]~=2.3.0
qiskit-ibm-runtime~=0.43.1
scipy~=1.16.3
Nota

Gli utenti del piano Open non possono inviare job in sessione. I workload devono essere eseguiti in modalità job o in modalità batch.

Usa le sessioni quando hai bisogno di un accesso dedicato ed esclusivo alla QPU.

Configurazione per usare le sessioni​

Prima di avviare una sessione, devi configurare Qiskit Runtime e inizializzarlo come servizio:

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

Aprire una sessione​

Puoi aprire una sessione di runtime usando il context manager with Session(...) oppure inizializzando la classe Session. Quando avvii una sessione, devi specificare una QPU passando un oggetto backend. La sessione inizia quando il suo primo job viene eseguito.

nota

Se apri una sessione ma non invii alcun job per 30 minuti, la sessione si chiude automaticamente.

Classe Session

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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()

Context manager

Il context manager apre e chiude la sessione automaticamente.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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()

Durata della sessione​

Il tempo di vita massimo della sessione (TTL) determina per quanto tempo può essere eseguita una sessione. Puoi impostare questo valore con il parametro max_time. Dovrebbe superare il tempo di esecuzione del job più lungo.

Questo timer parte quando la sessione inizia. Quando il valore viene raggiunto, la sessione viene chiusa. I job in esecuzione termineranno, ma quelli ancora in coda vengono annullati con errore.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità batch.

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

Esiste anche un valore di tempo di vita interattivo (interactive TTL) che non è configurabile. Se nessun job della sessione viene messo in coda entro quella finestra temporale, la sessione viene temporaneamente disattivata.

Valori predefiniti:

Tipo di istanza (piano Open o Premium)TTL interattivoTTL massimo
Piano Premium60 sec*8 h*
* Alcune istanze del piano Premium potrebbero essere configurate con un valore diverso.

Per determinare il TTL massimo o il TTL interattivo di una sessione, segui le istruzioni in Determinare i dettagli della sessione e cerca i valori max_time o interactive_timeout, rispettivamente.

Terminare una sessione​

Una sessione termina nelle seguenti circostanze:

  • Il valore massimo di timeout (TTL) viene raggiunto, con conseguente annullamento di tutti i job in coda.
  • La sessione viene annullata manualmente, con conseguente annullamento di tutti i job in coda.
  • La sessione viene chiusa manualmente. La sessione smette di accettare nuovi job ma continua a eseguire i job in coda con priorità.
  • Se usi Session come context manager, ovvero with Session(), la sessione viene chiusa automaticamente quando il contesto termina (stesso comportamento di session.close()).

Chiudere una sessione​

Una sessione si chiude automaticamente quando esce dal context manager. Quando il context manager della sessione viene abbandonato, la sessione passa allo stato "In corso, non accetta nuovi job". Ciò significa che la sessione termina l'elaborazione di tutti i job in esecuzione o in coda fino al raggiungimento del valore di timeout massimo. Dopo il completamento di tutti i job, la sessione viene chiusa immediatamente. Questo consente allo scheduler di eseguire il job successivo senza attendere il timeout interattivo della sessione, riducendo così il tempo medio di accodamento dei job. Non è possibile inviare job a una sessione chiusa.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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()
suggerimento

Se non stai usando un context manager, chiudi manualmente la sessione per evitare costi indesiderati. Puoi chiudere una sessione non appena hai finito di inviarle job. Quando una sessione viene chiusa con session.close(), non accetta più nuovi job, ma i job già inviati verranno comunque eseguiti fino al completamento e i loro risultati potranno essere recuperati.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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})

Verificare lo stato della sessione​

Puoi interrogare lo stato di una sessione per capirne la situazione attuale usando session.status() oppure consultando la pagina Workloads.

Lo stato della sessione può essere uno dei seguenti:

  • Pending: La sessione non è ancora iniziata o è stata disattivata. Il prossimo job della sessione deve attendere in coda come gli altri job.
  • In progress, accepting new jobs: La sessione è attiva e accetta nuovi job.
  • In progress, not accepting new jobs: La sessione è attiva ma non accetta nuovi job. L'invio di job alla sessione viene rifiutato, ma i job della sessione già in sospeso verranno eseguiti fino al completamento. La sessione viene chiusa automaticamente una volta terminati tutti i job.
  • Closed: Il valore di timeout massimo della sessione è stato raggiunto oppure la sessione è stata chiusa esplicitamente.

Determinare i dettagli della sessione​

Per una panoramica completa della configurazione e dello stato di una sessione, usa il metodo session.details().

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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}

Pattern di utilizzo​

Le sessioni sono particolarmente utili per gli algoritmi che richiedono frequenti scambi di dati tra risorse classiche e quantistiche.

Esempio: esegui un workload iterativo che usa l'ottimizzatore classico SciPy per minimizzare una funzione di costo. In questo modello, SciPy usa l'output della funzione di costo per calcolare il suo prossimo input.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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()

Eseguire due algoritmi VQE in una sessione usando il threading​

Puoi sfruttare al meglio una sessione eseguendo più workload contemporaneamente. L'esempio seguente mostra come eseguire due algoritmi VQE, ciascuno con un ottimizzatore classico diverso, simultaneamente all'interno di un'unica sessione. Vengono usati anche tag di job per distinguere i job dei diversi workload.

attenzione

Il seguente blocco di codice restituirà un errore agli utenti del piano Open perché utilizza le sessioni. I workload sul piano Open possono essere eseguiti solo in modalità job o in modalità 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()

Passi successivi​

Raccomandazioni