O async (launch :: async) em C ++ 11 torna os pools de threads obsoletos para evitar a criação de threads caras?

Está vagamente relacionado a esta questão:São std :: thread agrupados em C ++ 11?. Embora a questão seja diferente, a intenção é a mesma:

Pergunta 1: Ainda faz sentido usar seus próprios pools de threads (ou biblioteca de terceiros) para evitar a criação de segmentos caros?

A conclusão na outra questão era que você não pode confiarstd::thread para ser agrupado (pode ou pode não ser). Contudo,std::async(launch::async) parece ter uma chance muito maior de ser agrupada.

Não acho que é forçado pelo padrão, mas IMHO eu esperaria que todas as boas implementações de C ++ 11 usassem o conjunto de encadeamentos se a criação de encadeamentos fosse lenta. Apenas em plataformas onde é barato criar um novo thread, eu esperaria que eles sempre gerassem um novo thread.

Pergunta 2: Isso é exatamente o que eu penso, mas não tenho fatos para provar isso. Eu posso muito bem estar enganado. É um palpite educado?

Finalmente, aqui eu forneci um código de exemplo que primeiro mostra como eu acho que a criação de threads pode ser expressa porasync(launch::async):

Exemplo 1:

 thread t([]{ f(); });
 // ...
 t.join();

torna-se

 auto future = async(launch::async, []{ f(); });
 // ...
 future.wait();

Exemplo 2: atire e esqueça o thread

 thread([]{ f(); }).detach();

torna-se

 // a bit clumsy...
 auto dummy = async(launch::async, []{ f(); });

 // ... but I hope soon it can be simplified to
 async(launch::async, []{ f(); });

Questão 3: Você preferiria oasync versões para othread versões?

O resto não faz mais parte da questão, mas apenas para esclarecimentos:

Por que o valor de retorno deve ser atribuído a uma variável fictícia?

Infelizmente, o padrão C ++ 11 atual força a captura do valor de retorno destd::async, caso contrário, o destruidor é executado, bloqueando até que a ação termine. É por alguns considerado um erro no padrão (por exemplo, por Herb Sutter).

Este exemplo decppreference.com ilustra bem:

{
  std::async(std::launch::async, []{ f(); });
  std::async(std::launch::async, []{ g(); });  // does not run until f() completes
}

Outro esclarecimento:

Eu sei dissopools de threads podem ter outros usos legítimos, mas nesta questão eu estou interessado apenas no aspecto de evitar custos caros de criação de threads.

Acho que ainda existem situações em que os conjuntos de encadeamentos são muito úteis, especialmente se você precisar de mais controle sobre os recursos. Por exemplo, um servidor pode decidir manipular apenas um número fixo de solicitações simultaneamente para garantir tempos de resposta rápidos e aumentar a previsibilidade do uso da memória. As piscinas de linhas devem estar bem aqui.

Variáveis ​​thread-local também podem ser um argumento para seus próprios pools de threads, mas não tenho certeza se é relevante na prática:

Criando um novo thread comstd::thread inicia sem variáveis ​​de thread local inicializadas. Talvez isso não seja o que você quer.Em encadeamentos gerados porasync, é um pouco incerto para mim porque o segmento poderia ter sido reutilizado. Pelo que entendi, não é garantido que as variáveis ​​locais de thread sejam redefinidas, mas posso estar enganado.Por outro lado, usar seus próprios pools de threads (de tamanho fixo) oferece controle total se você realmente precisar.

questionAnswers(1)

yourAnswerToTheQuestion