Kuyruk mantığı — öncelik, bekleme süresi ve gönderim disiplini
Gerçek bir kuantum cihazı, aynı anda yalnızca tek bir devreyi yürütebilen kıt bir kaynaktır. Aynı backend'e dünyanın her yerinden yüzlerce kullanıcı iş gönderir; bu nedenle her iş, çalışmadan önce bir kuyrukta bekler. Kuyrukta bekleme süresi çoğu zaman, devrenin kendi yürütme süresinden kat kat uzundur — saniyelik bir Bell devresi için bile bir saat bekleyebilirsiniz. Bu sayfa kuyruk olgusunu uzun uzun açar: nasıl çalışır, öncelikler neden vardır, fair-share politikası ne işe yarar, session ve batch bu sırayı nasıl etkiler, "tahmini bekleme süresi" tahmininin sınırları nedir, gönderim zamanlamasını nasıl tasarlarız, üretimde kuyruğu nasıl gözlemleriz. Tüm kod örnekleri tamamen yereldir (Aer + FakeBackend); IBM kuyruğuna canlı bağlantı kuran hiçbir blok yoktur, yalnızca yorum hattında referans iskelet bulunur.
Kuyruk niçin vardır?
Kuyruk, kuantum donanımının fiziksel tekilliğinden doğan bir sonuçtur. Bir süperiletken çip aynı anda yalnızca tek bir devreyi yürütebilir; bu devre tamamlanmadan ikincisini başlatmak donanımın doğasına aykırıdır. Aynı çipi dünyanın farklı yerlerinden paylaşan onlarca, yüzlerce kullanıcı olduğunda, talep arzdan büyük olur ve iş sıraya girer. Bu sıra, donanımın kendisi kadar somut bir gerçekliktir; zamanı tahmin etmek, planlamak ve raporlamak kodu yazan kişinin sorumluluğundadır.
Süre = yürütme + bekleme
Bir Job nesnesinin yaşam döngüsünde RUNNING durumu çoğu zaman saniyeler sürer; QUEUED durumu ise saatlerce uzanabilir. Bu yüzden "X süresi alır" cümlesinin doğru kuşatması "kuyrukta Y dakika + çipte Z saniye" hâlindedir. Sadece Z'yi raporlamak, deneyimi küçümsemek olur.
Yerel simülatörde kuyruk yoktur
Aer ve FakeBackend üzerinde iş anında başlar; kuyruk olgusu öğrenilirken yereldeki bu "kuyruksuz" davranış kod yazımında bizi rahatlatır, ama üretime taşırken aldatıcı olabilir. Bu yüzden yerel testler, kuyruğun yokluğunda da kuyruğa dayanıklı bir mimariyle yazılmalıdır.
FIFO, öncelik ve fair-share
En basit kuyruk modeli FIFO'dur (first in, first out) — önce gelen önce işlenir. Gerçek hayatta saf FIFO, kuyruğa erken gelen büyük bir kullanıcının tüm zamanı tutmasına yol açar; bu nedenle çoğu büyük hizmet sağlayıcısı fair-share politikası uygular: aynı dönemde çok iş göndermiş kullanıcının sırası geriler, az iş göndermiş kullanıcı öne alınır. Bunun üzerine ücretli plan, kurum veya akademik proje gibi öncelik kanalları eklenir.
Öncelik = "daha hızlı" değil "daha az bekleyen"
Öncelik yükseltmek devrenin çipte daha hızlı çalışmasını sağlamaz; yalnızca kuyrukta daha önce işleme alınmasını sağlar. Çipteki yürütme süresi (kapı sayısı, shot sayısı, ölçüm, kalibrasyon turu) plandan bağımsızdır.
Fair-share ile kişisel deneyim
Aynı kullanıcının ardarda 50 iş göndermesi, son işlerin sırada belirgin biçimde gerilemesine yol açabilir. Bu olgu "kendi kendine kuyruk yapmak" olarak da görülebilir; iterasyon başına bir iş gönderen varyasyonel algoritmaların session ile sarılması bu yüzden sadece ağ değil, fair-share açısından da kazanım sağlar.
Session ve batch'in kuyruk üzerindeki etkisi
Session mantığı sayfasında anlattığımız gibi, bir session bağlı kanal açar; içindeki ardışık işler aynı pencerede işlenir, her biri için kuyruğa baştan girmek zorunda kalmaz. Bu, fair-share sayacının her iterasyonda artmaması anlamına da gelebilir. Batch ise tek bir gönderimde birden çok devrenin toplu paketlenmesidir; kuyruğa tek seferde tek girer, içinde N tane devre koşulur. İkisi de "kuyruğa N kez girmek yerine bir kez" demenin farklı yollarıdır.
Ne zaman session, ne zaman batch?
Bir iterasyonun çıktısı sonraki iterasyonun girişiyse (klasik optimizatör, VQE/QAOA gibi), session doğru seçimdir. Bağımsız devrelerin paralel listesi varsa (örneğin parametre taraması, devre kütüphanesi karşılaştırması), batch kuyruk başına maliyeti azaltır. Saf tekil bir iş için ikisinin de faydası yoktur — basit backend.run(...) yeterlidir.
Hibrit akışlar
Üretimde bu üç desen iç içe geçer: bir session içinde her iterasyon batch olabilir, session sonunda raporlama için ayrı bir ad-hoc job gönderilir. Bu hibrit tasarımı okunabilir tutmanın yolu, modü tek bir noktada (mode parametresi) tutmaktır.
Tahmini bekleme süresinin sınırları
Çoğu provider, gönderim öncesi veya sonrası bir tahmini bekleme süresi (estimated queue time) sunar. Bu sayı yararlı bir başlangıçtır fakat garanti değildir; geriye doğru gelen yüksek öncelikli işler, bakım pencereleri ya da beklenmedik hata sıçramaları tahmini kolayca bozar. Bu yüzden tahmin nokta değil aralık olarak okunmalı, raporlarda "tahmini X dk; gözlenen Y dk" şeklinde iki sayı birden tutulmalıdır.
Akşam saatleri ve hafta sonu
Doğal olarak, çok kullanıcılı bir kuyrukta gün içinde yoğun saatler ve sakin saatler oluşur. Saat dilimi, eğitim dönemi başlangıçları, konferans deadline'ları gibi etmenler doğrudan bekleme süresini etkiler. Bu hassasiyet, deneyleri ne zaman göndereceğinizi planlamak için pratik bir dayanaktır.
Süre değil, sıra
"10 dakika" tahmini bazen "60 dakika" çıkabilir; sebep çoğu zaman önümüze geçen birkaç uzun işin RUNNING aşamasında olmasıdır. Tahminin titreşimi olduğu varsayımıyla yazılan kod, sonradan değişen sayılarla "kırılmaz".
Gönderim zamanlaması ve "uyku saatleri"
Bir deneyi yarın sabahki rapor için yetiştirmek istiyorsanız, gönderim zamanlaması teknik kadar pratik bir karardır. Saat geç gece veya hafta sonu erken saatler — provider'ın kullanıcı yoğunluğunun düştüğü zamanlar — sıklıkla daha kısa kuyruk üretir. Pipeline'lar tipik olarak işleri yığar, sonra otomatik bir zamanlayıcıyla (cron, scheduler) gönderir; sabah sonuçlar hazır olur.
Pasif bekleme yerine aktif tasarım
Saatlerce result() ile kilitlenen bir hücre/script, ne ekibe ne donanıma faydadır. Doğru yol, işi gönderdikten sonra id'yi loglamak, ana akışı serbest bırakmak ve sonucu polling/callback ile almaktır. Bu disiplin job sistemi sayfasında anlatılan kalıbın doğal devamıdır.
Yeniden üretilebilir deney
Aynı algoritmayı farklı zamanlarda gönderdiğinizde sonuçların farklı çıkması, doğrudan algoritma hatası anlamına gelmez — kalibrasyon kayması veya farklı qubit ataması olabilir. "Gönderim saati", deney metadata'sının ihmal edilemez bir alanıdır.
Tek büyük iş mi, çok küçük iş mi?
Aynı toplam iş yükünü iki şekilde bölebilirsiniz: tek bir uzun gönderim (örneğin shot=8192) ya da sekiz adet kısa gönderim (her biri shot=1024). Kuyruk açısından tek iş bir kez sıraya girer; sekiz iş sekiz kez sıraya girer ve fair-share sayacınız yükselir. Bu yüzden eşit toplamda az ve büyük tercih edilir; ancak sonuçların iterasyon arası gözlemlenmesi gerekiyorsa, küçük parçalar açıkça fayda sunar (örneğin optimizatör erken durur). Karar, bilgi kazanımı ile kuyruk maliyetinin dengesidir.
Shot dağıtımı tasarımı
8 × 1024 yerine 1 × 8192 göndermek bazen mümkün değildir — bazı backend'ler tek iş başına shot tavanı uygular. Bu durumda tasarım batch hâline gelir: tek listede çok devre, her biri farklı parametre veya farklı shot bütçesiyle.
Maliyet okuması
"Bu deney bana ne maliyetli?" sorusunu yanıtlamak, sadece şot başına süre çarpımı değildir; kuyruktaki ardışık gönderimlerin sebep olduğu süre + fair-share gerilemesi de hesaba katılmalıdır. Raporlama dilinde iki satır: "donanım vakti" ve "kuyruk vakti".
Kuyruk gözlemi ve diyagnostik
Provider tarafında kuyruk durumu için tipik göstergeler: pending jobs (sıra uzunluğu), operational (donanım aktif mi), status_msg (bakım/uyarı mesajı), estimated_queue_time (tahmini bekleme). Bu alanlar doğrudan kuyruk politikasını açıklamasa da, gönderim öncesi karar için yeterlidir: "yoğun mu? bakım var mı? sıra ne kadar?".
Dashboard ve log
Üretim pipeline'ları, kendi tarafında basit bir dashboard tutar: gönderim saati, job_id, backend adı, beklenen bekleme, gerçekleşen bekleme, hata kodu. Sonradan bu küçük tablo, "bu algoritma neden geçen sefer 20 dk değil de 3 saat sürdü?" sorusunun cevabını verir.
Yedek backend stratejisi
Bir backend bakıma girerse veya sıra çok uzarsa, alternatif bir backend hazırda tutmak kullanıcı deneyimini korur. Bu karar backend seçimi sayfasındaki filtre/seçim disiplini ile birleşir.
Yerel öğretim modeli
Kuyruk öğrenilirken IBM cihazına bağlanmaya gerek yoktur. Eğitim amaçlı küçük bir simüle kuyruk sınıfı yazmak — işlerin sıraya alınması, tek tek işletilmesi, fair-share sayacının artması — gerçek kuyruğun davranışını kavramsal olarak yeniden üretir. Bu sınıf gerçek hizmetin yerine geçmez; ancak ekibe "kuyruk neyi nasıl yapar?" sorusunu anlatmak için ideal bir tahta-üzeri modeldir.
Gerçek hizmete köprü
Yerel modelin "submit / pop / run / done" döngüsü, üretimdeki "submit / queued / running / done" mantığına neredeyse birebir eşlenir. Yerelde kullandığınız metric'ler (sıra uzunluğu, başına süre, fair-share) provider tarafında karşılığını bulur. Bu yüzden öğretim modeli atılır mı? Hayır — basit bir izleme dashboard'unun temelidir.
Aer'i bir backend olarak kullanın
Öğretim modelinin "yürütücü" rolünü Aer üstlenir; "gerçek donanım" yerine "anında çalışan ideal cihaz" olarak görür. Devre cebrini bozmadan, yalnızca kuyruk katmanını taklit etmiş olursunuz.
Kod laboratuvarı
Üç blok da tamamen yereldir: ağ yok, IBM hesabı yok. Birinci blok küçük bir öğretim kuyruğu kurar (FIFO, fair-share sayacı, gönderim metadata'sı ile). İkinci blok aynı algoritmayı 1×8192 ve 8×1024 olarak gönderip "kuyruk başına" maliyet sezgisini taklit eder. Üçüncü blok, kuyruk durumuna bakıp uygun backend seçen küçük bir stratejiyi yerelde modellenir; bulut karşılığı yalnızca yorum hattında durur.
# from qiskit_ibm_runtime import QiskitRuntimeService
# service = QiskitRuntimeService()
# backend = service.backend("ibm_brisbane")
# status = backend.status() # canlı sorgu
# print("pending:", status.pending_jobs,
# "operational:", status.operational,
# "msg:", status.status_msg)
# # Yedek strateji:
# # candidates = service.backends(simulator=False, operational=True)
# # best = min(candidates, key=lambda b: b.status().pending_jobs)
from collections import deque, defaultdict
from dataclasses import dataclass, field
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
@dataclass
class QueuedJob:
user: str
circuit: QuantumCircuit
shots: int = 1024
counts: dict = field(default_factory=dict)
class TeachingQueue:
"""Tek yürütücü, FIFO sıra, basit fair-share sayacı.
Gerçek bir provider değildir; öğretim için modeldir."""
def __init__(self):
self.backend = AerSimulator()
self.pending = deque()
self.usage = defaultdict(int)
def submit(self, job: QueuedJob):
self.pending.append(job)
self.usage[job.user] += 1
print(f"+ submit user={job.user:>6} q_len={len(self.pending)} usage={self.usage[job.user]}")
def step(self):
if not self.pending:
return None
job = self.pending.popleft()
result = self.backend.run(job.circuit, shots=job.shots).result()
job.counts = result.get_counts()
print(f"- done user={job.user:>6} q_len={len(self.pending)} bits={len(job.counts)}")
return job
qc = QuantumCircuit(2, 2)
qc.h(0); qc.cx(0, 1); qc.measure([0, 1], [0, 1])
q = TeachingQueue()
for u in ("alice", "alice", "bob", "alice", "carol"):
q.submit(QueuedJob(user=u, circuit=qc, shots=256))
while q.pending:
q.step()
print("fair-share görünümü:", dict(q.usage))
import time
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
# Gerçek donanımda her gönderim ayrı bir kuyruk girişidir.
# Aer'de kuyruk yok, ama "kaç submit yaptım?" sezgisini takip edebiliriz.
QUEUE_ENTRY_PENALTY = 0.05 # sahte: gönderim başına 50 ms ek "kuyruk maliyeti"
def run_with_penalty(label, runs, shots_per_run):
backend = AerSimulator()
qc = QuantumCircuit(3, 3)
qc.h(0); qc.cx(0, 1); qc.cx(1, 2); qc.measure(range(3), range(3))
t0 = time.perf_counter()
total_counts = {}
for _ in range(runs):
time.sleep(QUEUE_ENTRY_PENALTY) # her submit ekstra maliyet
counts = backend.run(qc, shots=shots_per_run).result().get_counts()
for k, v in counts.items():
total_counts[k] = total_counts.get(k, 0) + v
dt = time.perf_counter() - t0
total_shots = runs * shots_per_run
print(f"{label:>14} runs={runs:>2} shots={total_shots} duration={dt:5.2f}s bits={len(total_counts)}")
run_with_penalty("1x8192", runs=1, shots_per_run=8192)
run_with_penalty("8x1024", runs=8, shots_per_run=1024)
from dataclasses import dataclass
from qiskit import QuantumCircuit, transpile
from qiskit_ibm_runtime.fake_provider import FakeManilaV2, FakeBelemV2
@dataclass
class FakeStatus:
name: str
pending_jobs: int
operational: bool = True
# Yerelde "kuyruk uzunluğu" elle simüle edilir.
catalog = [
(FakeManilaV2(), FakeStatus("fake_manila", pending_jobs=42)),
(FakeBelemV2(), FakeStatus("fake_belem", pending_jobs=7)),
]
def least_busy(catalog):
healthy = [(b, s) for b, s in catalog if s.operational]
if not healthy:
raise RuntimeError("Çalışan backend yok.")
return min(healthy, key=lambda pair: pair[1].pending_jobs)
backend, status = least_busy(catalog)
print(f"seçilen: {status.name} pending={status.pending_jobs}")
qc = QuantumCircuit(2, 2)
qc.h(0); qc.cx(0, 1); qc.measure([0, 1], [0, 1])
tqc = transpile(qc, backend=backend, optimization_level=2)
counts = backend.run(tqc, shots=512).result().get_counts()
print(f"counts: {counts}")
İleri okuma ve özet
Kuyruk, donanımın paylaşılabilirliğinin fiyatıdır. FIFO + fair-share + öncelik karışımı, "kaç bekledim, ne zaman bekledim, nasıl yumuşatabilirim?" sorularını birleştirir. Session ve batch, kuyruğa girme sayısını azaltır; tahmin titreşimlidir, raporda iki sayı tutun; gönderim zamanlaması ve yedek backend stratejisi, üretim akışlarının pratik kazanımıdır. Yerelde kurduğunuz öğretim modeli, üretim dashboard'unun temelidir.
- Job sistemi — asenkron tutamak ve durum makinesi.
- Session mantığı — bağlı kanal ve iteratif iş.
- Runtime yürütmesi — primitives ailesi.
- Backend seçimi ve provider sistemi — kuyruk ile birlikte planlama.
- Fake backend kullanımı — yerel öğretim hedefleri.
- Aer simülatörü ve shot mantığı — yürütme ve istatistik.