Panduan ini menjelaskan model threading yang digunakan oleh library klien C++, dan menunjukkan cara mengganti kumpulan thread default di aplikasi Anda.
Tujuan
- Jelaskan model threading default untuk library klien C++.
- Jelaskan cara mengganti setelan default ini untuk aplikasi yang perlu melakukannya.
Mengapa library klien menggunakan thread latar belakang?
Sebagian besar fungsi di library klien menggunakan thread yang memanggil fungsi untuk menyelesaikan semua pekerjaan, termasuk RPC ke layanan dan/atau memperbarui token akses untuk autentikasi.
Fungsi asinkron, secara alami, tidak dapat menggunakan thread saat ini untuk menyelesaikan tugasnya. Beberapa thread terpisah harus menunggu hingga pekerjaan selesai dan menangani respons.
Memblokir thread panggilan pada operasi yang berjalan lama juga merupakan pemborosan, karena layanan mungkin memerlukan waktu beberapa menit atau lebih lama untuk menyelesaikan tugas. Untuk operasi tersebut, library klien menggunakan thread latar belakang untuk melakukan polling secara berkala terhadap status operasi yang berjalan lama.
Fungsi dan library apa yang memerlukan thread latar belakang?
Fungsi yang menampilkan future<T> untuk beberapa jenis T menggunakan thread latar belakang untuk menunggu hingga tugas selesai.
Tidak semua library klien memiliki fungsi asinkron atau operasi yang berjalan lama. Library yang tidak memerlukannya tidak membuat thread latar belakang.
Anda mungkin melihat thread tambahan di aplikasi Anda, tetapi thread ini mungkin dibuat oleh dependensi library klien C++, seperti gRPC. Thread ini biasanya kurang menarik, karena tidak ada kode aplikasi yang berjalan di thread ini dan hanya menjalankan fungsi tambahan.
Bagaimana pengaruh thread latar belakang ini terhadap aplikasi saya?
Seperti biasa, thread ini bersaing untuk mendapatkan resource CPU dan memori dengan aplikasi Anda lainnya. Jika diperlukan, Anda dapat membuat thread pool sendiri untuk mendapatkan kontrol yang lebih baik atas resource yang digunakan oleh thread ini. Lihat detailnya di bawah.
Apakah ada kode saya yang berjalan di salah satu thread ini?
Ya. Saat Anda melampirkan callback ke future<T>, callback hampir selalu
dieksekusi oleh salah satu thread latar belakang. Satu-satunya kasus di mana hal ini tidak akan
terjadi adalah jika future<T> sudah terpenuhi pada saat Anda melampirkan
callback. Dalam hal ini, callback akan segera berjalan dalam konteks
thread yang melampirkan callback.
Misalnya, pertimbangkan aplikasi yang menggunakan library klien Pub/Sub.
Panggilan Publish() menampilkan future dan aplikasi dapat melampirkan callback
setelah melakukan beberapa tugas:
namespace pubsub = ::google::cloud::pubsub;
namespace g = google::cloud;
void Callback(g::future<g::StatusOr<std::string>>);
void F(pubsub::Publisher publisher) {
auto my_future = publisher.Publish(
pubsub::MessageBuilder("Hello World!").Build());
// do some work.
my_future.then(Callback);
}
Jika my_future terpenuhi sebelum fungsi .then() dipanggil, maka
callback akan segera dipanggil. Jika ingin menjamin kode berjalan di thread terpisah, Anda harus menggunakan thread pool sendiri dan memberikan callable di .then() yang meneruskan eksekusi ke thread pool Anda.
Kumpulan Thread Default
Untuk library yang memerlukan thread latar belakang, Make*Connection()
membuat kumpulan thread default. Kecuali jika Anda mengganti kumpulan thread, setiap objek *Connection memiliki kumpulan thread terpisah.
Kumpulan thread default di sebagian besar library berisi satu thread. Lebih banyak thread jarang diperlukan karena thread latar belakang digunakan untuk melakukan polling status operasi yang berjalan lama. Panggilan ini berdurasi cukup singkat dan menggunakan CPU yang sangat sedikit, sehingga satu thread latar belakang dapat menangani ratusan operasi yang berjalan lama yang tertunda, dan hanya sedikit aplikasi yang memiliki operasi sebanyak itu.
Operasi asinkron lainnya mungkin memerlukan lebih banyak resource.
Gunakan GrpcBackgroundThreadPoolSizeOption untuk mengubah ukuran kumpulan thread latar belakang default jika diperlukan.
Library Pub/Sub diharapkan memiliki lebih banyak tugas, karena aplikasi Pub/Sub biasanya menerima atau mengirim ribuan pesan per detik. Oleh karena itu, library ini secara default menggunakan satu thread per core pada arsitektur 64-bit. Pada arsitektur 32-bit (atau saat dikompilasi dalam mode 32-bit, meskipun berjalan di arsitektur 64-bit), nilai default ini berubah menjadi hanya 4 thread.
Menyediakan Kumpulan Thread Anda sendiri
Anda dapat menyediakan kumpulan thread Anda sendiri untuk thread latar belakang. Buat objek
CompletionQueue, lampirkan thread ke objek tersebut, dan konfigurasi
GrpcCompletionQueueOption saat menginisialisasi klien Anda. Contoh:
namespace admin = ::google::cloud::spanner_admin;
namespace g = ::google::cloud;
void F() {
// You will need to create threads
auto cq = g::CompletionQueue();
std::vector<std::jthread> threads;
for (int i = 0; i != 10; ++i) {
threads.emplace_back([](auto cq) { cq.Run(); }, cq);
}
auto client = admin::InstanceAdminClient(admin::MakeInstanceAdminConnection(
g::Options{}.set<g::GrpcCompletionQueueOption>(cq)));
// Use `client` as usual
}
Anda dapat membagikan objek CompletionQueue yang sama di beberapa klien, bahkan untuk layanan yang berbeda:
namespace admin = ::google::cloud::spanner_admin;
namespace pubsub = ::google::cloud::pubsub;
namespace g = ::google::cloud;
void F(pubsub::Topic const& topic1, pubsub::Topic const& topic2) {
// You will need to create threads
auto cq = g::CompletionQueue();
std::vector<std::jthread> threads;
for (int i = 0; i != 10; ++i) {
threads.emplace_back([](auto cq) { cq.Run(); }, cq);
}
auto client = admin::InstanceAdminClient(admin::MakeInstanceAdminConnection(
g::Options{}.set<g::GrpcCompletionQueue>(cq)));
auto p1 = pubsub::Publisher(pubsub::MakePublisherConnection(
topic1, g::Options{}.set<g::GrpcCompletionQueueOption>(cq)));
auto p2 = pubsub::Publisher(pubsub::MakePublisherConnection(
topic2, g::Options{}.set<g::GrpcCompletionQueueOption>(cq)));
// Use `client`, `p1`, and `p2` as usual
}
Langkah Berikutnya
- Lihat Konfigurasi Library Klien untuk mempelajari lebih lanjut opsi konfigurasi library umum.
- Lihat Library Klien C++ Cloud Pub/Sub untuk dokumentasi referensi library klien Pub/Sub lengkap.