Topik wawancara representatif

Wawancara Koding C++26: Bagaimana Cara Mengimplementasikan Pipeline Multi-Scheduler yang Aman dari Pembatalan?

CodingSulit
Tim Redaksi Offer.ccDipublikasikan Diperbarui

Pertanyaan

Implementasikan pipeline pembacaan, transformasi paralel, dan agregasi dengan std::execution C++26. Bagaimana cara Anda beralih scheduler, membatasi konkurensi, mempropagasi penghentian, serta menjaga status operasi dan sumber daya tetap hidup hingga selesai?

Petunjuk dan keberlakuan

Sebuah layanan harus menyusun proses pembacaan, transformasi, dan agregasi ke dalam sebuah pipeline asinkron. Pemanggil dapat membatalkan karena batas waktu (timeout), pemutusan koneksi, atau tekanan sumber daya; setiap tahap dapat gagal saat pekerjaan lain sedang berjalan. Gunakan model sender/receiver std::execution C++26 untuk menjelaskan penjadwalan, sinyal penyelesaian, masa hidup (lifetime), dan jalur fallback.

Ini menguji batasan dari abstraksi konkurensi, bukan menghafal sintaks dari satu pustaka tertentu. Pustaka execution-control standar memisahkan grafik kerja sender dari penanganan penyelesaian receiver dan menggunakan status operasi (operation state) untuk status asinkron yang terhubung. Jawaban yang kuat menjadikan pembatalan, semantik kesalahan, dan pembersihan sebagai kontrak yang eksplisit.

Hal yang diuji oleh pewawancara

  • Membedakan lazy sender, operation state yang terhubung, dan eksekusi aktual pada start.
  • Merepresentasikan sumber daya eksekusi dengan scheduler alih-alih membuat thread ad hoc dalam kode bisnis.
  • Menangani set_value, set_error, dan set_stopped secara terpisah daripada menyamarkan pembatalan sebagai sebuah eksepsi.
  • Mempropagasikan permintaan penghentian melalui setiap tahap dan mencegah efek samping baru setelah penghentian.
  • Menjelaskan backpressure, batas limit, keamanan eksepsi, dan agregasi untuk pekerjaan paralel.
  • Menyediakan deteksi kapabilitas, lapisan kompatibilitas, dan pengujian yang konsisten ketika pustaka standar tidak tersedia.

Klarifikasi yang perlu ditanyakan terlebih dahulu

  1. Apakah pembacaan berasal dari berkas lokal, permintaan jaringan, atau kursor basis data? Apakah tahapan dapat diulang atau memiliki efek samping eksternal?
  2. Apakah pembatalan berarti berhenti dengan segera, berhenti setelah panggilan yang tidak dapat diinterupsi selesai, atau membatalkan (roll back) hasil yang telah di-commit?
  3. Apa saja batasan untuk paralelisme, memori, batas waktu per item, dan batas waktu keseluruhan (deadline)?
  4. Apakah agregasi harus mempertahankan urutan input, hasil floating-point yang stabil, atau hasil parsial yang terlihat?
  5. Apakah kompilator dan pustaka target mengimplementasikan eksekusi C++26, atau hanya implementasi eksperimental?

Jawaban 30 detik

Saya akan mendefinisikan kontrak penyelesaian dengan saluran value, error, dan stopped. Pembatalan mencegah pekerjaan yang belum dimulai dan memungkinkan tahapan yang dapat diinterupsi untuk merespons dengan cepat. Setiap sender tetap bersifat lazy; menghubungkan (connecting) akan membuat operation state, dan start memulai eksekusi. Scheduler eksplisit memiliki sumber daya eksekusi, sementara batas paralelisme dan antrean melindungi memori. Agregator mendefinisikan aturan pengurutan dan hasil parsial. Deteksi kapabilitas memilih implementasi standar, pustaka kompatibilitas, atau jalur skalar sinkron, dengan pengujian bersama untuk pembatalan, kesalahan, dan hasil.

Pembahasan mendalam langkah demi langkah

1. Gambar grafik kerja yang lazy

Hubungkan sender pembacaan ke sender transformasi dan kemudian ke sender agregasi. then meneruskan nilai yang dihasilkan ke node berikutnya, let_value dapat membuat operasi asinkron lain dari suatu hasil, dan when_all merepresentasikan cabang-cabang paralel. Komposisi membangun sebuah grafik; komposisi tidak boleh melakukan I/O selama konstruksi.

2. Definisikan koneksi dan masa hidup (lifetime)

connect antara sender dan receiver akan membuat operation state; eksekusi hanya diizinkan setelah start. Alamat operation state harus tetap valid hingga operasi asinkron selesai, sehingga tidak boleh berada di stack frame yang akan segera kembali (return). Konteks permintaan atau scope asinkron harus memilikinya dan melepaskan sumber daya pada jalur value, error, dan stopped.

3. Berikan sumber daya ke scheduler

Scheduler adalah handle ringan untuk sumber daya eksekusi. Tempatkan pembacaan pada sumber daya I/O dan transformasi CPU pada sumber daya paralel yang dibatasi; gunakan on, starts_on, atau continues_on untuk menyatakan batas-batas tahapan. Jangan membuat satu thread per elemen. Batasi paralelisme, panjang antrean, dan ukuran batch untuk mengontrol memori dan peralihan konteks (context switching).

4. Propagasikan stopped, error, dan value

Penyelesaian value berlanjut ke tahap berikutnya, error masuk ke penanganan kesalahan terpadu, dan stopped masuk ke penanganan pembatalan. Token penghentian (stop token) pada environment receiver adalah titik observasi pembatalan. Panggilan sistem yang memblokir (blocking system calls) memerlukan antarmuka yang dapat diinterupsi atau batas waktu terbatas; jika tidak, panggilan tersebut hanya dapat merespons setelah kembali. Pembatalan bukanlah rollback: setelah penulisan eksternal terjadi, gunakan kunci idempoten, kompensasi, atau batas ireversibel yang eksplisit.

5. Sketsa komposisi minimal

Kode ini menunjukkan bentuk grafik; sender pembacaan dan thread-pool sebenarnya disediakan oleh proyek.

cpp
using namespace std::execution;

auto pipeline = read_sender()
  | let_value([](Batch batch) {
      return bulk_transform(batch, get_parallel_scheduler());
    })
  | then([](Transformed value) { return summarize(value); })
  | upon_error([](std::exception_ptr error) { record_failure(error); })
  | upon_stopped([] { record_cancellation(); });

auto state = connect(std::move(pipeline), receiver);
start(state);

Receiver harus dimiliki oleh scope permintaan aktif yang menyediakan stop token di environment-nya. Kode produksi juga harus mencatat tahap, batch, batas waktu, dan alasan pembatalan alih-alih hanya menampilkan kegagalan umum.

6. Agregasi paralel dan batasan efek samping

Pertahankan status lokal per-tugas selama transformasi paralel dan gabungkan dalam urutan yang ditentukan saat agregasi. Jika penggabungan tidak berurutan diizinkan, nyatakan perbedaan yang disebabkan oleh operasi floating-point yang tidak asosiatif; jika output yang stabil diperlukan, pertahankan indeks atau urutan partisi. Periksa stop token sebelum penulisan eksternal dan catat kunci idempoten setelah commit. set_stopped bukan berarti commit tersebut dibatalkan.

7. Fallback, pengujian, dan observabilitas

Bangun matriks dari makro uji fitur, versi kompilator, dan kapabilitas pustaka. Jika eksekusi standar tidak tersedia, implementasi kompatibilitas dapat mempertahankan kontrak sender internal; jika tidak, gunakan thread pool terbatas atau jalur sinkron sambil menjaga semantik value, error, dan stopped tetap konsisten. Uji input kosong, batch parsial, pembatalan berulang, perlombaan (race) error-versus-stop, kehabisan sumber daya, penghancuran dini operation state, dan pemulaian berulang. Lakukan benchmark pada throughput, tail latency, panjang antrean, waktu respons pembatalan, dan tugas yang belum selesai.

Contoh jawaban berkualitas tinggi

Saya akan memodelkan pipeline sebagai grafik sender yang lazy: pembacaan, transformasi paralel, dan agregasi masing-masing mengekspos tanda tangan penyelesaian (completion signatures), kemudian connect membuat operation state dan start mengeksekusinya. I/O dan CPU menggunakan scheduler yang berbeda, dengan batas paralelisme, antrean, dan batch. Receiver menangani value, error, dan stopped secara terpisah; setiap titik yang dapat diinterupsi memeriksa stop token. Penulisan eksternal menggunakan batasan idempoten dan kompensasi, sehingga pembatalan tidak pernah menjanjikan rollback.

Scope permintaan memiliki operation state hingga selesai, dan jalur error maupun stopped sama-sama menjalankan pembersihan. Toolchain mendeteksi eksekusi C++26 dan memilih standar, implementasi kompatibilitas, atau fallback sinkron. Semua jalur berbagi pengujian perilaku untuk batch kosong, race condition, respons pembatalan, kehabisan sumber daya, dan penghancuran dini. Di lingkungan produksi, saya akan memantau tail latency, kedalaman antrean, respons pembatalan, dan kebocoran untuk memverifikasi bahwa paralelisme benar-benar meningkatkan metrik target.

Kesalahan umum

  • Menganggap konstruksi sender sebagai awal dari pekerjaan asinkron.
  • Membiarkan operation state mati ketika fungsi kembali (return).
  • Hanya menggunakan saluran eksepsi dan memperlakukan pembatalan sebagai kesalahan biasa.
  • Membuat satu thread per elemen tanpa batas antrean, paralelisme, atau memori.
  • Mengklaim efek samping eksternal telah di-rollback ketika sinyal penghentian tiba.
  • Membiarkan aturan pengurutan, toleransi floating-point, atau hasil parsial tidak terdefinisi untuk agregasi paralel.
  • Hanya mengimplementasikan satu jalur pustaka standar tanpa deteksi kapabilitas atau fallback.

Pertanyaan lanjutan dan tanggapan

Kapan sender benar-benar berjalan?

Komposisi mendeskripsikan sebuah grafik. Menghubungkan (connecting) akan membuat operation state, dan start memulai operasi asinkron. Pengujian harus mencakup konstruksi, koneksi, dan pemulaian secara terpisah.

Bisakah permintaan penghentian menghentikan panggilan sistem secara paksa?

Secara umum tidak bisa. Panggilan tersebut membutuhkan antarmuka yang dapat diinterupsi, batas waktu (timeout), atau pemeriksaan bertahap (chunked checks). Jika tidak, panggilan tersebut baru merespons setelah kembali, dan waktu respons terburuk harus diukur.

Bagaimana jika error dan stop terjadi bersamaan?

Tentukan prioritas dan aturan penyelesaian tunggal sehingga receiver melihat tepat satu sinyal terminal. Pertahankan kesalahan asli dan alasan penghentian untuk kebutuhan diagnosis.

Apa yang terjadi jika salah satu cabang dari when_all gagal?

Tentukan apakah cabang lain terus berjalan, menerima permintaan penghentian, atau menyelesaikan pembersihan. Sumber daya bersama memerlukan kepemilikan berlingkup (scoped ownership) dan propagasi pembatalan; agregator tidak boleh membaca hasil cabang yang tidak valid.

Bagaimana cara membuat agregasi dapat direproduksi (reproducible)?

Pertahankan nomor urut partisi dan gabungkan dalam urutan tetap, atau izinkan hasil tidak berurutan secara eksplisit dengan batas toleransi kesalahan. Reduksi paralel tidak dapat mengasumsikan sifat asosiatif floating-point.

Bagaimana jika pustaka produksi tidak memiliki eksekusi C++26?

Gunakan matriks kapabilitas kompilator untuk memilih implementasi kompatibilitas atau jalur sinkron sambil tetap mempertahankan semantik penyelesaian dan pengujian. Jangan mengekspos tipe privat dari pustaka eksperimental dalam antarmuka publik.

Sumber publik

Pertanyaan terkait

Alat wawancara terkait

Gunakan Tangkapan Layar untuk perintah coding

Ambil tangkapan layar soal, lalu telusuri batasan, solusi, kode, edge case, dan kompleksitas secara berurutan.

Lihat alat