Nie mam wszystkich odpowiedzi. Mam nadzieję, że mogę rzucić na to trochę światła.
Aby uprościć moje poprzednie stwierdzenia dotyczące modeli wątków .NET, wystarczy wiedzieć, że Parallel Library używa Tasks, a domyślny TaskScheduler dla Tasks używa ThreadPool. Im wyżej w hierarchii (ThreadPool znajduje się na dole), tym więcej narzutów masz przy tworzeniu elementów. To dodatkowe obciążenie z pewnością nie oznacza, że jest wolniejsze, ale dobrze wiedzieć, że tam jest. Ostatecznie wydajność twojego algorytmu w środowisku wielowątkowym sprowadza się do jego konstrukcji. To, co działa dobrze sekwencyjnie, może nie działać równie dobrze równolegle. Jest zbyt wiele czynników, aby dać ci twarde i szybkie reguły, zmieniają się w zależności od tego, co próbujesz zrobić. Ponieważ zajmujesz się żądaniami sieci, postaram się podać mały przykład.
Pozwól mi powiedzieć, że nie jestem ekspertem od gniazd i nie wiem prawie nic o Zeroc-Ice. Wiem trochę o operacjach asynchronicznych i właśnie tam naprawdę ci to pomoże. Jeśli wyślesz żądanie synchroniczne przez gniazdo, podczas połączenia Socket.Receive()
Twój wątek zostanie zablokowany do momentu otrzymania żądania. To nie jest dobre. Wątek nie może wysyłać więcej żądań, ponieważ jest zablokowany. Za pomocą Socket.Beginxxxxxx () żądanie I / O zostanie wykonane i umieszczone w kolejce IRP dla gniazda, a Twój wątek będzie kontynuowany. Oznacza to, że Twój wątek może faktycznie wysyłać tysiące żądań w pętli bez żadnego blokowania!
Jeśli dobrze cię rozumiem, używasz wywołań za pomocą Zeroc-Ice w kodzie testowym, a nie próbujesz dotrzeć do punktu końcowego http. W takim przypadku mogę przyznać, że nie wiem, jak działa Zeroc-Ice. Chciałbym jednak zasugerować po poradę wymienionych tutaj , zwłaszcza część: Consider Asynchronous Method Invocation (AMI)
. Strona pokazuje to:
Korzystając z AMI, klient odzyskuje wątek kontroli, gdy tylko wywołanie zostanie wysłane (lub, jeśli nie można go wysłać natychmiast, zostanie umieszczone w kolejce), umożliwiając klientowi użycie tego wątku do wykonania innej użytecznej pracy w międzyczasie .
Co wydaje się być odpowiednikiem tego, co opisałem powyżej przy użyciu gniazd .NET. Mogą istnieć inne sposoby poprawy wydajności, gdy próbuję wykonać wiele wysyłek, ale zacznę tutaj lub z dowolnymi innymi sugestiami wymienionymi na tej stronie. Byłeś bardzo niejasny co do projektu swojej aplikacji, więc mogę być bardziej szczegółowy niż wcześniej. Pamiętaj tylko, że nie używaj więcej wątków, niż jest to absolutnie konieczne, aby uzyskać to, czego potrzebujesz, w przeciwnym razie aplikacja będzie działać wolniej niż chcesz.
Kilka przykładów w pseudokodzie (próbowałem zbliżyć się do lodu, jak to możliwe, ale ja nie musiałem się go uczyć):
var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
// The thread blocks here waiting for the response.
// That slows down your loop and you're just wasting
// CPU cycles that could instead be sending/receiving more objects
MyObjectPrx obj = iceComm.stringToProxy("whateverissupposedtogohere");
obj.DoStuff();
}
Lepszy sposób:
public interface MyObjectPrx : Ice.ObjectPrx
{
Ice.AsyncResult GetObject(int obj, Ice.AsyncCallback cb, object cookie);
// other functions
}
public static void Finished(Ice.AsyncResult result)
{
MyObjectPrx obj = (MyObjectPrx)result.GetProxy();
obj.DoStuff();
}
static void Main(string[] args)
{
// threaded code...
var iterations = 100000;
for (int i = 0; i < iterations; i++)
{
int num = //whatever
MyObjectPrx prx = //whatever
Ice.AsyncCallback cb = new Ice.AsyncCallback(Finished);
// This function immediately gets called, and the loop continues
// it doesn't wait for a response, it just continually sends out socket
// requests as fast as your CPU can handle them. The response from the
// server will be handled in the callback function when the request
// completes. Hopefully you can see how this is much faster when
// sending sockets. If your server does not use an Async model
// like this, however, it's quite possible that your server won't
// be able to handle the requests
prx.GetObject(num, cb, null);
}
}
Pamiętaj, że więcej wątków! = Lepsza wydajność podczas próby wysłania gniazd (lub naprawdę robiąc cokolwiek). Wątki nie są magiczne, ponieważ automatycznie rozwiążą każdy problem, nad którym pracujesz. Idealnie, chcesz 1 wątek na rdzeń, chyba że wątek spędza dużo czasu na oczekiwaniu, możesz uzasadnić, że masz więcej. Uruchamianie każdego żądania w jego własnym wątku jest złym pomysłem, ponieważ nastąpi zmiana kontekstu i marnowanie zasobów. (Jeśli chcesz zobaczyć wszystko, co o tym napisałem, kliknij edytuj i spójrz na poprzednie wersje tego postu. Usunąłem go, ponieważ wydawało się, że tylko zasłania główny problem.)
Zdecydowanie możesz je wysłać w wątkach, jeśli chcesz wysyłać dużą liczbę żądań na sekundę. Jednak nie przesadzaj z tworzeniem wątków. Znajdź równowagę i trzymaj się jej. Osiągniesz lepszą wydajność, jeśli użyjesz modelu asynchronicznego w porównaniu z modelem synchronicznym.
Mam nadzieję że to pomogło.