2011-08-13 31 views
7

TL; DR: Reaktör üretiminin sınırlı olması mümkün mü? Nasıl anlarım? Ne kadar pahalı ve ölçeklenebilir (iplikler arası) io_service'nin uygulamasıdır?Boost ASIO reaktörü, tek bir çekirdeğe kısıtlanmaktan nasıl kaçınılır?

Tonlarca RAM ve hızlı bir SSD RAID içeren bir hiper iş parçacıklı çift-dört çekirdekli Xeon makinesinde çalışan çok güçlü bir paralel uygulamanız var. Bu, boost :: asio kullanılarak geliştirilmiştir.

Bu uygulama, yaklaşık 1.000 diğer makinelerden bağlantıları kabul verileri okur, basit bir protokol kodunu çözer ve dosyalar halinde karıştırır veri işlevi kullanacak eşleştirilmiş(). Uygulama aynı zamanda "gelecekteki" mmap sayfalarını madvise (WILLNEED) kullanarak önceden getiriyor, bu yüzden sayfa hatalarında engellenmesi olası değil, ancak emin olmak için 300 iş parçacığına kadar yumurtlamayı denedim.

Bu

Linux çekirdeği 2.6.32-27-jenerik (Ubuntu Sunucu x64 LTS 10,04) üzerinde çalışıyor. Gcc sürümü 4.4.3 ve boost :: asio sürümü 1.40'tır (her ikisi de stok Ubuntu LTS'dir).

vmstat, iostat ve en Çalıştırma, O, disk malzemesinin (TPS ve veri hacmi hem de)% tek basamaklı olduğunu görmek. Benzer şekilde, disk sıra uzunluğu her zaman iş parçacığı sayısından çok daha küçüktür, bu yüzden G/Ç bağlı olduğumu düşünmüyorum. Ayrıca, RSS tırmanıyor ama sonra birkaç konser (beklendiği gibi) stabilize ve vmstat hiçbir sayfalama, bu yüzden bellek bağlı değilim hayal ediyorum. CPU% 0-1 kullanıcı,% 6-7 sistem ve geri kalanı rölantide sabittir. İpucu! Bir tam "çekirdek" (hyper-threading'i hatırlar) CPU'nun% 6.25'i.

Ben 64kB daha üstün olduğunu ve gerçeği rapor istemci makineleri TCP gönderme engelle çünkü sistem, arkasında düşüyor biliyoruz; hepsi bu gerçeği bildirmeye devam ediyorlar ve sisteme olan verim istenilenden daha az, amaçlanmış ve teorik olarak mümkün.

Tahminimce bir çeşit kilit üzerinde çalışıyorum. Mutasyona uğrayabilecek bir arama tablosunu korumak için uygulama düzeyinde bir kilit kullanıyorum, bu yüzden bu bağımlılığı kırmak için bunu 256 üst düzey kilit/tabloya dönüştürdüm. Ancak, bu hiç yardımcı olmadı.

Tüm iletiler bir, global io_service örneğinden geçer. Uygulamadaki stresi çalıştırmak, zamanının çoğunu, io_service reaktörünün olay bazlı uygulamalarıyla ilgili olması gerektiğini düşündüğüm futex çağrılarıyla uğraştığını gösteriyor.

Reaktör çıkışı sınırlı mıyım? Nasıl anlarım? Ne kadar pahalı ve ölçeklenebilir (iplikler arası) io_service'nin uygulamasıdır?

DÜZENLEME: Başlangıçta bu diğer iş parçacığı bulamadım çünkü bu benim üst üste gelmeyen bir etiket kümesi kullanmıştı: -/Sorun şu ki, boost :: asio uygulamasında kullanılan aşırı kilitleme reaktör. C++ Socket Server - Unable to saturate CPU 'a bakın. Ancak, soru şu şekilde kalır: Bunu nasıl ispatlayabilirim? Ve bunu nasıl düzeltebilirim?

+1

Asio'nun yeni sürümlerini kullanarak performansı karşılaştırdınız mı? Boost 1,40 biraz eski ve [oldukça yakın zamanda] entegre bazı güzel gelişmeler vardı (http://think-async.com/Asio/LinuxPerformanceImprovements). –

+0

Ubuntu 10.04 LTS kullanmak için biraz daha kısıtlıyım. Bunu daha modern bir sistemde test edebilirim, ancak yine de stokta 10.04'te konuşlandırmam gerekiyor. Bence boost :: asio sadece başlıklar, belki de bu iş için yapılabilir ... –

+1

Sam: En son yayınlanan Boost'la çalıştım, 1.47.0. Yine de aynı sorun var - performans, tek bir CPU çekirdeğini aşmayı reddediyor (tüm çekirdekler aslında biraz engellenmiş olsa da, aslında bir iş yapıyor olsa da). –

cevap

2

cevap aslında o hatta en son boost :: asio sadece bir defada birden fazla iplikle çekirdeği girerek, tek bir iplikten epoll dosya niteleyicisine çağırır olduğunu. Nedenini anlayabiliyorum, çünkü her biri aynı dosya tanıtıcısı için bildirim alabilen çok sayıda iş parçacığı kullandığınızda, iş parçacığı güvenliği ve nesnelerin kullanım ömrü son derece risklidir. Bunu kendim kodladığımda (pthreads kullanarak), çalışır ve tek bir çekirdeğin ötesinde ölçekler. Boost :: asio'nun bu noktada kullanılmaması - aksi takdirde iyi tasarlanmış ve taşınabilir bir kütüphanenin bu sınırlamaya sahip olması bir utançtır.

+0

bunu biraz genişletebilir, ör. Bu kaynakta görülebilir nerede? Ben sadece merak ediyorum. :) – murrekatt

+0

@Jon, ASIO ** 'nin tasarımının **' io_service '* iş parçacığı başına bir * olduğunu belirlemesi olabilir mi? Ve sadece bir kolaylık olarak kilitleme sağlar, böylece programınız başarısız olmaz mı? – unixman83

+0

Tam tersine. ASIO API'sı, çalışmanın aynı io_service'ye giren tüm iş parçacıkları arasında paylaşılacağını söylüyor - bu, ASIO'nun bütün noktası. Nesne başına bildirimler yeniden sipariş verilebildiğinde, sorun gerçekten nesnelerin kullanım ömrüdir. –

2

Tek bir iş parçacığı tarafından işletilen her, bu sorun olmayacak, birden io_service nesne kullanırsanız (her cpu çekirdek için söylemek) inanıyoruz. Yükseltme ASIO sayfasındaki http sunucusu örneği 2'ye bakın.

Sunucu örneği 2 ve sunucu örneği 3'e karşı çeşitli karşılaştırmalar yaptım ve bahsettiğim uygulamanın en iyi çalıştığını öğrendim.

+0

Sorun, her I/O nesnesinin (zamanlayıcı, soket, vb.) AFAICT olan io_service'de gönderilmesi gerektiğidir. Soketleri iş parçacığına statik olarak ayırmak, yapmak istediğim bir şey değil. –

0

Tek iş parçacıklı uygulamamda, profil işlemlerinin büyük bir kısmının io_service :: poll() tarafından kilitleme ve kilidin açılması için harcanması gerektiğini öğrendim. Kilit işlemlerini BOOST_ASIO_DISABLE_THREADS makrosuyla devre dışı bıraktım. Diş çekme durumunuza bağlı olarak sizin için de mantıklı olabilir.

+0

İş parçacığı desteğini devre dışı bıraktığınızda, yalnızca tek bir iş parçacığı ile çalıştırabilirsiniz; bu, yalnızca tek bir çekirdekle sınırlı kalmama hedefine ulaşamayacaktır. –

+0

Neden iplik başına bir io_service kullanmıyorsunuz ve hala kilitsiz kalıyorsunuz? Bu geçersiz kullanım durumu mu? – Syncopated

+0

Bu, tüm işlerin genelinde tüm işlerin ölçeklendirilmesi amacını ortadan kaldırır. Soketlerin ve benzerlerinin yapıcıdaki belirli bir io_service'ye bağlı olduğunu unutmayın. –

İlgili konular