Pular para o conteúdo principal

Executar jobs em uma sessão

Versões dos pacotes

O código nesta página foi desenvolvido usando os seguintes requisitos. Recomendamos usar estas versões ou mais recentes.

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

Usuários do Open Plan não podem enviar jobs de sessão. As cargas de trabalho devem ser executadas no modo job ou no modo batch.

Use sessões quando você precisar de acesso dedicado e exclusivo ao QPU.

Configurar para usar sessões

Antes de iniciar uma sessão, você deve configurar o Qiskit Runtime e inicializá-lo como serviço:

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

Abrir uma sessão

Você pode abrir uma sessão de runtime usando o gerenciador de contexto with Session(...) ou inicializando a classe Session. Ao iniciar uma sessão, você deve especificar um QPU passando um objeto backend. A sessão começa quando seu primeiro job inicia a execução.

nota

Se você abrir uma sessão, mas não enviar nenhum job a ela por 30 minutos, a sessão é fechada automaticamente.

Classe Session

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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()

Gerenciador de contexto

O gerenciador de contexto abre e fecha a sessão automaticamente.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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()

Duração da sessão

O tempo de vida máximo da sessão (TTL) determina por quanto tempo uma sessão pode ser executada. Você pode definir esse valor com o parâmetro max_time. Esse valor deve ser superior ao tempo de execução do job mais longo.

Este temporizador começa quando a sessão inicia. Quando o valor é atingido, a sessão é encerrada. Os jobs que estiverem em execução serão concluídos, mas os jobs ainda na fila serão cancelados com falha.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo batch.

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

Há também um valor de tempo de vida interativo (TTL interativo) que não pode ser configurado. Se nenhum job de sessão for enfileirado dentro desse intervalo, a sessão é temporariamente desativada.

Valores padrão:

Tipo de instância (Open ou Premium Plan)TTL interativoTTL máximo
Premium Plan60 seg*8 h*
* Certas instâncias do Premium Plan podem ser configuradas com um valor diferente.

Para determinar o TTL máximo ou o TTL interativo de uma sessão, siga as instruções em Determinar detalhes da sessão e procure pelo valor max_time ou interactive_timeout, respectivamente.

Encerrar uma sessão

Uma sessão é encerrada nas seguintes circunstâncias:

  • O valor máximo de timeout (TTL) é atingido, resultando no cancelamento de todos os jobs na fila.
  • A sessão é cancelada manualmente, resultando no cancelamento de todos os jobs na fila.
  • A sessão é fechada manualmente. A sessão para de aceitar novos jobs, mas continua executando os jobs na fila com prioridade.
  • Se você usar Session como gerenciador de contexto, ou seja, with Session(), a sessão é fechada automaticamente quando o contexto termina (o mesmo comportamento de usar session.close()).

Fechar uma sessão

Uma sessão é fechada automaticamente quando sai do gerenciador de contexto. Quando o gerenciador de contexto da sessão é encerrado, a sessão entra no status "Em andamento, não aceitando novos jobs". Isso significa que a sessão termina de processar todos os jobs em execução ou na fila até que o valor máximo de timeout seja atingido. Depois que todos os jobs forem concluídos, a sessão é imediatamente fechada. Isso permite que o agendador execute o próximo job sem aguardar o timeout interativo da sessão, reduzindo assim o tempo médio de fila dos jobs. Você não pode enviar jobs para uma sessão fechada.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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()
dica

Se você não estiver usando um gerenciador de contexto, feche a sessão manualmente para evitar custos indesejados. Você pode fechar uma sessão assim que terminar de enviar jobs a ela. Quando uma sessão é fechada com session.close(), ela não aceita mais novos jobs, mas os jobs já enviados ainda serão executados até a conclusão e seus resultados podem ser recuperados.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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})

Verificar o status da sessão

Você pode consultar o status de uma sessão para entender seu estado atual usando session.status() ou acessando a página Workloads.

O status da sessão pode ser um dos seguintes:

  • Pending: A sessão não foi iniciada ou foi desativada. O próximo job de sessão precisa aguardar na fila como outros jobs.
  • In progress, accepting new jobs: A sessão está ativa e aceitando novos jobs.
  • In progress, not accepting new jobs: A sessão está ativa, mas não está aceitando novos jobs. O envio de jobs à sessão é rejeitado, mas os jobs de sessão pendentes serão executados até a conclusão. A sessão é fechada automaticamente quando todos os jobs terminarem.
  • Closed: O valor máximo de timeout da sessão foi atingido ou a sessão foi explicitamente fechada.

Determinar os detalhes da sessão

Para uma visão geral completa da configuração e do status de uma sessão, use o método session.details().

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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}

Padrões de uso

As sessões são especialmente úteis para algoritmos que exigem comunicação frequente entre recursos clássicos e quânticos.

Exemplo: Execute uma carga de trabalho iterativa que usa o otimizador clássico SciPy para minimizar uma função de custo. Neste modelo, o SciPy usa a saída da função de custo para calcular sua próxima entrada.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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()

Executar dois algoritmos VQE em uma sessão usando threading

Você pode aproveitar mais de uma sessão executando múltiplas cargas de trabalho simultaneamente. O exemplo a seguir mostra como você pode executar dois algoritmos VQE, cada um usando um otimizador clássico diferente, simultaneamente dentro de uma única sessão. Tags de job também são usadas para diferenciar os jobs de cada carga de trabalho.

cuidado

O bloco de código a seguir retornará um erro para usuários do Open Plan porque usa sessões. As cargas de trabalho no Open Plan só podem ser executadas no modo job ou no modo 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()

Próximos passos

Recomendações