Jest to luźno związane z tym pytaniem: czy std :: thread jest w puli w C ++ 11? . Chociaż pytanie jest inne, intencja jest taka sama:
Pytanie 1: Czy nadal ma sens używanie własnych (lub biblioteki innej firmy) pul wątków, aby uniknąć kosztownego tworzenia wątków?
Wniosek z drugiego pytania był taki, że nie można liczyć na std::threadto, że zostaniemy połączeni (może lub nie). std::async(launch::async)Wydaje się jednak, że ma znacznie większą szansę na połączenie.
Nie wydaje mi się, że jest to wymuszone przez standard, ale IMHO spodziewałbym się, że wszystkie dobre implementacje C ++ 11 będą używać puli wątków, jeśli tworzenie wątków jest powolne. Tylko na platformach, na których tworzenie nowego wątku jest niedrogie, spodziewałbym się, że zawsze tworzą nowy wątek.
Pytanie 2: Tak właśnie myślę, ale nie mam faktów, aby to udowodnić. Mogę się bardzo mylić. Czy to zgadywanie?
Na koniec przedstawiłem tutaj przykładowy kod, który najpierw pokazuje, jak myślę, że tworzenie wątków można wyrazić za pomocą async(launch::async):
Przykład 1:
thread t([]{ f(); });
// ...
t.join();
staje się
auto future = async(launch::async, []{ f(); });
// ...
future.wait();
Przykład 2: odpal i zapomnij wątek
thread([]{ f(); }).detach();
staje się
// a bit clumsy...
auto dummy = async(launch::async, []{ f(); });
// ... but I hope soon it can be simplified to
async(launch::async, []{ f(); });
Pytanie 3: Czy wolisz asyncwersje od threadwersji?
Reszta nie jest już częścią pytania, ale tylko dla wyjaśnienia:
Dlaczego wartość zwracana musi być przypisana do zmiennej fikcyjnej?
Niestety, obecny standard C ++ 11 wymusza przechwycenie zwracanej wartości std::async, ponieważ w przeciwnym razie wykonywany jest destruktor, który blokuje się do momentu zakończenia akcji. Niektórzy uważają to za błąd w normie (np. Przez Herba Suttera).
Ten przykład z cppreference.com ładnie to ilustruje:
{
std::async(std::launch::async, []{ f(); });
std::async(std::launch::async, []{ g(); }); // does not run until f() completes
}
Kolejne wyjaśnienie:
Wiem, że pule wątków mogą mieć inne uzasadnione zastosowania, ale w tym pytaniu interesuje mnie tylko aspekt unikania kosztownych kosztów tworzenia wątków .
Myślę, że nadal istnieją sytuacje, w których pule wątków są bardzo przydatne, zwłaszcza jeśli potrzebujesz większej kontroli nad zasobami. Na przykład serwer może zdecydować o obsłudze tylko określonej liczby żądań jednocześnie, aby zagwarantować szybkie czasy odpowiedzi i zwiększyć przewidywalność wykorzystania pamięci. Pule wątków powinny być w porządku.
Zmienne lokalne wątku mogą być również argumentem dla twoich własnych pul wątków, ale nie jestem pewien, czy ma to zastosowanie w praktyce:
- Tworzenie nowego wątku ze
std::threadstartami bez zainicjowanych zmiennych lokalnych wątku. Może nie tego chcesz. - W wątkach utworzonych przez program
asyncjest dla mnie niejasny, ponieważ wątek mógł zostać ponownie użyty. Z mojego zrozumienia nie ma gwarancji, że zmienne lokalne wątku zostaną zresetowane, ale mogę się mylić. - Z drugiej strony korzystanie z własnych pul wątków (o stałym rozmiarze) zapewnia pełną kontrolę, jeśli naprawdę tego potrzebujesz.
std::async(). Nadal jestem ciekawy, jak obsługują nietrywialne destruktory thread_local w puli wątków.
launch::async to traktuje ją tak, jakby była tylko launch::deferredi nigdy nie wykonuje jej asynchronicznie - w efekcie ta wersja libstdc ++ „wybiera” zawsze używać odroczonego, chyba że wymuszono inaczej.
std::asyncmógł być piękną rzeczą dla wydajności - mógł to być standardowy system wykonywania krótkich zadań, naturalnie wspierany przez pulę wątków. W tej chwili jest to tylko std::threadz przyczepionymi bzdurami, aby funkcja wątku mogła zwrócić wartość. Aha, i dodali zbędną „odroczoną” funkcjonalność, która std::functioncałkowicie pokrywa się z zadaniem .
std::async(launch::async)Wydaje się jednak, że ma znacznie większe szanse na połączenie." Nie, uważam,std::async(launch::async | launch::deferred)że to może być połączone. Samolaunch::asynczadanie ma zostać uruchomione w nowym wątku, niezależnie od tego, jakie inne zadania są uruchomione. Dzięki politycelaunch::async | launch::deferredimplementacja wybiera, którą politykę, ale co ważniejsze, może opóźnić wybór tej polityki. Oznacza to, że może poczekać, aż wątek w puli wątków stanie się dostępny, a następnie wybrać zasadę asynchronizacji.