[multi-threading] Incrementar número de threads simultâneas por processo

346 views
Skip to first unread message

Fernando Gomes

unread,
Apr 10, 2008, 3:17:40 PM4/10/08
to ccppbrasil
Caros,

      Pode ser um pouco off-topic - pois acho eu que a questão está relacionado ao OS Scheduller - mas após fazer algumas experiências com um código portável entre FreeBSD, Linux e Win32 onde fiz códigos com QThreads,  Pthreads, Boost Thread e outro com wxThread e numa mesma máquina tive resultados bastantes parecidos...

         350 threads no Linux Ubuntu e OpenSuse
       1800 threads no Windows XP
       3600 threads no FreeBSD

      Andei pesquisando a razão de tanta diferença entre threads simultâneas num processo por OS não consegui chegar a uma boa conclusão do porque tamanha diferença, alguém poderia me dar alguma pista que eu pudesse seguir para pesquisar melhor?

      Que caminho eu deveria seguir para conseguir alocar mais threads simultâneas por processo no Linux?

      Aos colegas que trabalham com C++ e com alta-perfomance, o que vcs costumam utilizar quando vcs necessitam fazer algo similar?

     Desde já grato.

[]s

./Fer -G0

Rodrigo Strauss

unread,
Apr 10, 2008, 3:25:31 PM4/10/08
to ccppb...@googlegroups.com
Mmm.... Por que você precisaria de mais do que 350 threads? O intuito
é só testar os limites ou de fato usar isso em um software?

No caso do linux você consegue alocar mais 350 threads em outro
processo simultaneamente ou o limite é da máquina? É interessante
lembrar que a implementação de threads é bem diferente entre Windows e
Linux. Se eu entendi bem o "Linux Kernel for Total Dummies", uma
thread no Linux é mais "cara" do que no Windows (assim como o processo
no Windows é muito mais "caro" que no Linux).

Rodrigo Strauss

2008/4/10 Fernando Gomes <fer...@googlemail.com>:

Felipe Magno de Almeida

unread,
Apr 10, 2008, 3:26:10 PM4/10/08
to ccppb...@googlegroups.com
2008/4/10 Fernando Gomes <fer...@googlemail.com>:

> Caros,
>
> Pode ser um pouco off-topic - pois acho eu que a questão está
> relacionado ao OS Scheduller - mas após fazer algumas experiências com um
> código portável entre FreeBSD, Linux e Win32 onde fiz códigos com QThreads,
> Pthreads, Boost Thread e outro com wxThread e numa mesma máquina tive
> resultados bastantes parecidos...
>
> 350 threads no Linux Ubuntu e OpenSuse
> 1800 threads no Windows XP
> 3600 threads no FreeBSD
>
> Andei pesquisando a razão de tanta diferença entre threads simultâneas
> num processo por OS não consegui chegar a uma boa conclusão do porque
> tamanha diferença, alguém poderia me dar alguma pista que eu pudesse seguir
> para pesquisar melhor?
>
> Que caminho eu deveria seguir para conseguir alocar mais threads
> simultâneas por processo no Linux?

WOW. Pra que vc precisa de tantas threads? Provavelmente vc está
usando o projeto errado.
Se você está preocupado com espera de I/O, dê uma olhada no boost.asio
para asynchronous I/O, que
diminui o uso de threads, e portanto o overhead associado a elas:
stack space, sincronizacao e
troca de contexto.

> Aos colegas que trabalham com C++ e com alta-perfomance, o que vcs
> costumam utilizar quando vcs necessitam fazer algo similar?

Eu começo a pensar em como resolver o problema de forma diferente.

>
> Desde já grato.
>
> []s
>
> ./Fer -G0

--
Felipe Magno de Almeida

Psycho Mantys

unread,
Apr 10, 2008, 3:36:23 PM4/10/08
to ccppb...@googlegroups.com


Em 10/04/08, Fernando Gomes <fer...@googlemail.com> escreveu:
#######################################################################################

Rapazzz, deixa ver se eu entendi: Você quer alocar mais do que 350 threads? Colocar mais de 350 linhas de execução? Cara, eu invejo voce :p. Essa maquina que vc tem deve dar medo neh? 200 processadores eh? :D

deixando a brincadeira de lado: Acho que isso tem a ver com uma stack de thread. No linux vc tem um tamanho determinado pelo kernel, se vc quiser mais, tem que ter um kernel que suporte mais(recompilar talvez).

E oq eu acho.


--
Adote um pinguim, saiba como! Me mande um e-mail demonstrando interesse!

http://www.slackware.com
http://img365.imageshack.us/img365/8483/snapshot3ak6.png
U.L. : 450347
Fnord

Rodrigo Kumpera

unread,
Apr 10, 2008, 3:37:30 PM4/10/08
to ccppb...@googlegroups.com
O limite de threads está relacionado ao tamanho reservado para a pilha. O default do linux é muito maior que dos outros SOs. Você pode diminuir ele usando pthread_attr_setstacksize no pthread_attr_t usado para criar a thread.

Aqui em casa com Open Suse 64 bits consigo criar 20 mil threads paradas sem problema limitando o stack de cada uma em 64K. Não que isso seja útil enquanto eu não tiver umas 500x mais cores que hoje.

Se você precisa de tanta linhas de execução simultâneas provavelmente não vai ser apenas com threads do SO que vai resolver.

Se o teu problema envolve o processamento de muitos sockets, muito melhor é usar o padrão Reactor com IO assíncrona ou multiplexada. O resultado é excelente e costuma ter baixa latência - já vi roteador de VOIP serem escritos assim - e usando Java que possui uma quota superior de latência muito maior.

Porém se o seu problema não se resume a muitos canais de IO a solução pode ser usar threads cooperativas com userland scheduling, dá um belo trabalho implementar, principalmente por não ser possível aplicar CPS em código C ou C++. Mas é possível tranquilamente escalar para dezenas de milhares de threads em máquinas com 4 cores com um overhead de scheduling baixo.



2008/4/10 Fernando Gomes <fer...@googlemail.com>:

Psycho Mantys

unread,
Apr 10, 2008, 3:48:44 PM4/10/08
to ccppb...@googlegroups.com


Em 10/04/08, Rodrigo Kumpera <kum...@gmail.com> escreveu:
O limite de threads está relacionado ao tamanho reservado para a pilha. O default do linux é muito maior que dos outros SOs. Você pode diminuir ele usando pthread_attr_setstacksize no pthread_attr_t usado para criar a thread.

Aqui em casa com Open Suse 64 bits consigo criar 20 mil threads paradas sem problema limitando o stack de cada uma em 64K. Não que isso seja útil enquanto eu não tiver umas 500x mais cores que hoje.

Se você precisa de tanta linhas de execução simultâneas provavelmente não vai ser apenas com threads do SO que vai resolver.

Se o teu problema envolve o processamento de muitos sockets, muito melhor é usar o padrão Reactor com IO assíncrona ou multiplexada. O resultado é excelente e costuma ter baixa latência - já vi roteador de VOIP serem escritos assim - e usando Java que possui uma quota superior de latência muito maior.

Porém se o seu problema não se resume a muitos canais de IO a solução pode ser usar threads cooperativas com userland scheduling, dá um belo trabalho implementar, principalmente por não ser possível aplicar CPS em código C ou C++. Mas é possível tranquilamente escalar para dezenas de milhares de threads em máquinas com 4 cores com um overhead de scheduling baixo.


[split]

Hummm. Sabia que tinha que ter lido todos os componentes dessa struct... Boa Kumpera..

Rodrigo:


No caso do linux você consegue alocar mais 350 threads em outro
processo simultaneamente ou o limite é da máquina? É interessante
lembrar que a implementação de threads é bem diferente entre Windows e
Linux. Se eu entendi bem o "Linux Kernel for Total Dummies", uma
thread no Linux é mais "cara" do que no Windows (assim como o processo
no Windows é muito mais "caro" que no Linux).

Voce esta falando do kernel 2.4 neh? O 2.6 isso foi "corrigido"(mudado), os threads não são mais "processos leves"(nao lembro o tipo desses thread) com memoria compartilhada, agora eles são threads leves. Pelo menos e isso que me lembro.

Gianni

unread,
Apr 10, 2008, 3:54:15 PM4/10/08
to ccppb...@googlegroups.com

> Voce esta falando do kernel 2.4 neh? O 2.6 isso foi "corrigido"(mudado), os
> threads não são mais "processos leves"(nao lembro o tipo desses thread) com
> memoria compartilhada, agora eles são threads leves. Pelo menos e isso que
> me lembro.
Bom, o post original falava de Ubuntu, que, se não me engano, desde sempre
usou 2.6

Cesar Mello

unread,
Apr 10, 2008, 3:54:38 PM4/10/08
to ccppb...@googlegroups.com
Outra sugestão é usar um thread pool, já que a performance provavelmente só vai ficar pior a partir de determinado número de threads.
 
Defina um thread pool de digamos, 20 threads, e sempre q precisar de uma thread nova aguarde uma das threads do pool ser liberada.
 
[]
Mello


 
2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:

Psycho Mantys

unread,
Apr 10, 2008, 4:03:11 PM4/10/08
to ccppb...@googlegroups.com


Em 10/04/08, Cesar Mello <cme...@gmail.com> escreveu:
######################################################################################


> Voce esta falando do kernel 2.4 neh? O 2.6 isso foi "corrigido"(mudado), os
> threads não são mais "processos leves"(nao lembro o tipo desses thread) com
> memoria compartilhada, agora eles são threads leves. Pelo menos e isso que
> me lembro.

Não e isso Gianny.

Me referi ao comentario sobre threads no kernel 2.4, e não sobre o cara usar o 2.6.

;)

Fernando Gomes

unread,
Apr 10, 2008, 4:17:25 PM4/10/08
to ccppb...@googlegroups.com

      Kumpera, você está chegando onde eu queria...

Em 10/04/08, Rodrigo Kumpera <kum...@gmail.com> escreveu:
O limite de threads está relacionado ao tamanho reservado para a pilha. O default do linux é muito maior que dos outros SOs. Você pode diminuir ele usando pthread_attr_setstacksize no pthread_attr_t usado para criar a thread.


 Cara, vou tentar descobrir como fazer isto com o Boost Thread e no  QThread, mas vc chegou no ponto onde eu queria.


Aqui em casa com Open Suse 64 bits consigo criar 20 mil threads paradas sem problema limitando o stack de cada uma em 64K. Não que isso seja útil enquanto eu não tiver umas 500x mais cores que hoje.

   
     Vc já tentou ver quantas threads simultâneas vc consegue deixar em pseudo-execução?

Psycho Mantys

unread,
Apr 10, 2008, 4:31:02 PM4/10/08
to ccppb...@googlegroups.com
Em 10/04/08, Fernando Gomes <fer...@googlemail.com> escreveu:
#####################################################################################

Eu creio que voce fica limitado ao tamanho de um "size_t" para a stack. Entao voce nao pode ter mais que isso.
Mas se voce fizer com pthread, vai servir para o resto(qthreads e similares) a nao ser que o modo seja de implementação de thread seja diferente.

Pelo menos e o que eu acho.

Rodrigo Kumpera

unread,
Apr 10, 2008, 4:31:41 PM4/10/08
to ccppb...@googlegroups.com


2008/4/10 Fernando Gomes <fer...@googlemail.com>:


      Kumpera, você está chegando onde eu queria...

Em 10/04/08, Rodrigo Kumpera <kum...@gmail.com> escreveu:
O limite de threads está relacionado ao tamanho reservado para a pilha. O default do linux é muito maior que dos outros SOs. Você pode diminuir ele usando pthread_attr_setstacksize no pthread_attr_t usado para criar a thread.


 Cara, vou tentar descobrir como fazer isto com o Boost Thread e no  QThread, mas vc chegou no ponto onde eu queria.


Aqui em casa com Open Suse 64 bits consigo criar 20 mil threads paradas sem problema limitando o stack de cada uma em 64K. Não que isso seja útil enquanto eu não tiver umas 500x mais cores que hoje.

   
     Vc já tentou ver quantas threads simultâneas vc consegue deixar em pseudo-execução?

Depende do workload, pois isso vai ditar qual vai ser a carga média do sistema. Quando o objetivo é maximizar o throughput do sistema o ideal é tunar para mantar o load o mais próximo do número de cpus lógicas do sistema*.

Para cargas que não dependem de IO e são puramente computacionais usar uma thread por core resolve. Porém se você for implementar algo no qual cada thread irá passar boa parte do tempo esperando, o número pode chega a uma centena sem degradar muito. Um servidor HTTP com uma aplicação web, por exemplo, não existe muito problema em uma uma centena de threads se a maior parte do tempo será gasta enviando/recebendo dados da rede e conversando com o banco de dados.

Porém se você precisa lidar com centenas de conecções persistentes (um servidor de jabber, por exemplo) pode ser melhor usar algo como reactor com uma thread em listen e um pool tratando as que tem alguma mensagem.

Isso tudo, claro, que se você não tem requisitos especiais como baixa latência ou consumo de memória.

*Com SMT isso não é trivial porém.


Hugo Parente Lima

unread,
Apr 10, 2008, 4:41:40 PM4/10/08
to ccppb...@googlegroups.com
On Thursday 10 April 2008 17:17:25 Fernando Gomes wrote:
> Kumpera, você está chegando onde eu queria...
>
> Em 10/04/08, Rodrigo Kumpera <kum...@gmail.com> escreveu:
> > O limite de threads está relacionado ao tamanho reservado para a pilha. O
> > default do linux é muito maior que dos outros SOs. Você pode diminuir ele
> > usando pthread_attr_setstacksize no pthread_attr_t usado para criar a
> > thread.
>
> Cara, vou tentar descobrir como fazer isto com o Boost Thread e no
> QThread, mas vc chegou no ponto onde eu queria.
>

Com QThread talvez usando QThread::currentThreadId() dê para fazer algo não
portável... mas antes você tem que fazer um trabalho de mineração no código
fonte da Qt para saber o que tem no danado do Qt::HANDLE que esse método
retorna na plataforma que vc estiver usando... se a pthreads usar alguma
variável de ambiente para saber o tamanho da pilha que vai usar seria melhor
ainda.

> --~--~---------~--~----~------------~-------~--~----~
> C/C++ Brasil - http://www.cbrasil.org/
> Para sair dessa lista, envie um e-mail para
> ccppbrasil-...@googlegroups.com Para mais opções, visite
> http://groups.google.com/group/ccppbrasil
> -~----------~----~----~----~------~----~------~--~---

--
Hugo Parente Lima
"Precisamos de mais gênios humildes no mundo, hoje somos poucos!"
JID: hu...@jabber.org

signature.asc

Felipe Magno de Almeida

unread,
Apr 10, 2008, 4:42:26 PM4/10/08
to ccppb...@googlegroups.com
2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:
>

[snip]

> > Vc já tentou ver quantas threads simultâneas vc consegue deixar em
> pseudo-execução?
> >
>
> Depende do workload, pois isso vai ditar qual vai ser a carga média do
> sistema. Quando o objetivo é maximizar o throughput do sistema o ideal é
> tunar para mantar o load o mais próximo do número de cpus lógicas do
> sistema*.

E o minimo de context switches possiveis.

> Para cargas que não dependem de IO e são puramente computacionais usar uma
> thread por core resolve. Porém se você for implementar algo no qual cada
> thread irá passar boa parte do tempo esperando, o número pode chega a uma
> centena sem degradar muito. Um servidor HTTP com uma aplicação web, por
> exemplo, não existe muito problema em uma uma centena de threads se a maior
> parte do tempo será gasta enviando/recebendo dados da rede e conversando com
> o banco de dados.

Nao existe problema em termos né. É um grande overhead desperdiçado,
nao vejo muito sentido em fazer algo desse tipo.

> Porém se você precisa lidar com centenas de conecções persistentes (um
> servidor de jabber, por exemplo) pode ser melhor usar algo como reactor com
> uma thread em listen e um pool tratando as que tem alguma mensagem.

Sou mais usar um Proactor, tanto pra jabber quanto pra HTTP. Eu mesmo
uso este pattern
através do asio para implementar um cliente de SMTP de alta performance.

> Isso tudo, claro, que se você não tem requisitos especiais como baixa
> latência ou consumo de memória.

Mesmo nao tendo requisto de pouca memória, desperdiça-la em 100
threads é na minha opiniao um pouco irresponsável.

> *Com SMT isso não é trivial porém.

SMT? Nao vejo menção a SMT no resto da thread. Perdi algo da discussao?

[]'s

Rodrigo Kumpera

unread,
Apr 10, 2008, 5:04:46 PM4/10/08
to ccppb...@googlegroups.com


2008/4/10 Felipe Magno de Almeida <felipe.m...@gmail.com>:


2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:
>

[snip]

> >      Vc já tentou ver quantas threads simultâneas vc consegue deixar em
> pseudo-execução?
> >
>
> Depende do workload, pois isso vai ditar qual vai ser a carga média do
> sistema. Quando o objetivo é maximizar o throughput do sistema o ideal é
> tunar para mantar o load o mais próximo do número de cpus lógicas do
> sistema*.

E o minimo de context switches possiveis.

> Para cargas que não dependem de IO e são puramente computacionais usar uma
> thread por core resolve. Porém se você for implementar algo no qual cada
> thread irá passar boa parte do tempo esperando, o número pode chega a uma
> centena sem degradar muito. Um servidor HTTP com uma aplicação web, por
> exemplo, não existe muito problema em uma uma centena de threads se a maior
> parte do tempo será gasta enviando/recebendo dados da rede e conversando com
> o banco de dados.

Nao existe problema em termos né. É um grande overhead desperdiçado,
nao vejo muito sentido em fazer algo desse tipo.
 
Eu vejo, é muito mais fácil programar de maneira síncrona. Escrever um programa usando
thread-per-socket é muito mais fácil, rápido e confiável que outro usando qualquer outra
técnica de I/O.

Quando o tempo do processamento de cada requisição é grande (0.2s user+kernel time) o overhead de context switching
com 100 threads é desprezível. Já fui pelos dois camínhos e num final abandonei a implementação.

Minha experiência foi ao implementar um servidor de SMTP. A diferença do custo para implementár e dar manutenção usando thread-per-socket e proactor não se justifica, sai mais barato comprar mais hardware.


> Porém se você precisa lidar com centenas de conecções persistentes (um
> servidor de jabber, por exemplo) pode ser melhor usar algo como reactor com
> uma thread em listen e um pool tratando as que tem alguma mensagem.

Sou mais usar um Proactor, tanto pra jabber quanto pra HTTP. Eu mesmo
uso este pattern
através do asio para implementar um cliente de SMTP de alta performance.

Ótima sugestão, proactor também é uma ótima forma de implementar servidores com poucas threads.
 

> Isso tudo, claro, que se você não tem requisitos especiais como baixa
> latência ou consumo de memória.

Mesmo nao tendo requisto de pouca memória, desperdiça-la em 100
threads é na minha opiniao um pouco irresponsável.

Irresponsável? Memória é estupidamente barato hoje em dia. 100 thread vão te custar uns 200Mb de ram no pior caso - que por sinal significa que o programa tem muitos outros problemas para usar ativamente 2Mb de stack! Ainda mais hoje que servidores com 4Gb de ram é perfeitamente normal.
 

> *Com SMT isso não é trivial porém.

SMT? Nao vejo menção a SMT no resto da thread. Perdi algo da discussao?

[]'s


SMT em Symetric Multi Threading. Calcular o load ótimo na presença de SMT não é trivial já que duas ou mais threads no mesmo core passam a interferir no padrão de acesso a memória entre sí.


Felipe Magno de Almeida

unread,
Apr 10, 2008, 5:12:40 PM4/10/08
to ccppb...@googlegroups.com
2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:
>

[snip]

> >


> > Nao existe problema em termos né. É um grande overhead desperdiçado,
> > nao vejo muito sentido em fazer algo desse tipo.
>
> Eu vejo, é muito mais fácil programar de maneira síncrona. Escrever um
> programa usando
> thread-per-socket é muito mais fácil, rápido e confiável que outro usando
> qualquer outra
> técnica de I/O.

Nao concordo completamente. Utilizar multi-threading incorre muitos
outros problemas também, como
sincronizacao de recursos compartilhados. Com a ferramenta certa (asio
+ finite state machine) é muito facil
implementar utilizando asynchronous IO.

> Quando o tempo do processamento de cada requisição é grande (0.2s
> user+kernel time) o overhead de context switching
> com 100 threads é desprezível. Já fui pelos dois camínhos e num final
> abandonei a implementação.

Certamente em SMTP existe bastante context switching, é só contar quantos
comandos sao trocados antes de se fazer qualquer coisa útil, e ainda
tem o acesso a disco que
também deve ser feito assincronamente. Com certeza a versao com thread pool
nao escala tanto quanto utilizando asynchronous IO para acessos simultâneos.

> Minha experiência foi ao implementar um servidor de SMTP. A diferença do
> custo para implementár e dar manutenção usando thread-per-socket e proactor
> não se justifica, sai mais barato comprar mais hardware.

Sua experiencia foi certamente diferente da minha.

[snip]

> > Mesmo nao tendo requisto de pouca memória, desperdiça-la em 100
> > threads é na minha opiniao um pouco irresponsável.
>
> Irresponsável? Memória é estupidamente barato hoje em dia. 100 thread vão te
> custar uns 200Mb de ram no pior caso - que por sinal significa que o
> programa tem muitos outros problemas para usar ativamente 2Mb de stack!
> Ainda mais hoje que servidores com 4Gb de ram é perfeitamente normal.

4GB recebendo ou enviando mensagens de 200MB é pouquinho ;).
Esse argumento é o mesmo que os javeiros usam. E mesmo assim
usar programas java me incomoda muito. Só nao incomoda o desenvolvedor
eu presumo.

[snip]

> > SMT? Nao vejo menção a SMT no resto da thread. Perdi algo da discussao?
> >
> > []'s
>
>
> SMT em Symetric Multi Threading. Calcular o load ótimo na presença de SMT
> não é trivial já que duas ou mais threads no mesmo core passam a interferir
> no padrão de acesso a memória entre sí.

Ah sim. Valeu pela clarificação.

Rodrigo Kumpera

unread,
Apr 10, 2008, 6:04:12 PM4/10/08
to ccppb...@googlegroups.com
2008/4/10 Felipe Magno de Almeida <felipe.m...@gmail.com>:
2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:
>

[snip]

> >
> > Nao existe problema em termos né. É um grande overhead desperdiçado,
> > nao vejo muito sentido em fazer algo desse tipo.
>
> Eu vejo, é muito mais fácil programar de maneira síncrona. Escrever um
> programa usando
> thread-per-socket é muito mais fácil, rápido e confiável que outro usando
> qualquer outra
>  técnica de I/O.

Nao concordo completamente. Utilizar multi-threading incorre muitos
outros problemas também, como
sincronizacao de recursos compartilhados. Com a ferramenta certa (asio
+ finite state machine) é muito facil
implementar utilizando asynchronous IO.
 

Me corrija se estiver errado, mas mesmo usando AIO você tem os mesmos problemas de multi-threading se quiser escalar para múltiplos cores. Porém concordo contigo, escrever programas multi-threaded com C ou C++ é um raro tipo de tortura que deve ser evitado. Certamente usar AIO com uma FSM vai ser mais escalável, porém em alguns casos isso é otimizar as partes que não são o hotspot do programa. Ser 2x mais eficiente em 10% do programa só vai tornar o programa 5% mais rápido.  Como falei, o importante é avaliar a necessidade e os requisitos a serem implementados.

Quer um exemplo? Qualquer solução com AIO tem latência maior e eficiência menor que thread-per-socket. Os SOs modernos não conseguem fazer zero-copy-txer com aio assíncrona ou não bloqueante na maioria dos casos. Isso, claro, se tivermos menos sockets que cores. ;)


> Quando o tempo do processamento de cada requisição é grande (0.2s
> user+kernel time) o overhead de context switching
> com 100 threads é desprezível. Já fui pelos dois camínhos e num final
> abandonei a implementação.

Certamente em SMTP existe bastante context switching, é só contar quantos
comandos sao trocados antes de se fazer qualquer coisa útil, e ainda
tem o acesso a disco que
também deve ser feito assincronamente. Com certeza a versao com thread pool
nao escala tanto quanto utilizando asynchronous IO para acessos simultâneos.

Você parou para fazer as contas? Provavelmente não. Vou umar o linux como exemplo.
Usando uma thread por socket, cada uma usar 1 timeslice por comando, serão 3 context
switches por email enviado (MAIL TO, RCPT TO e DATA). Um context switch no linux
usa aproximadamente 2500 ciclos. Para um sistema que aceita mil emails por segundo,
isso são 1000 * 2500 * 3, ou 7.5Mhz. Com uma CPU de 2.4Ghz isso são 0.3% de economia.

Ainda assim, supondo que vamos ter melhor afinidade de cache e isso vai aumentar em dez vezes
o ganho, são só 3%! Desculpa, mas todo tem algo melhor para fazer que ficar se esfolando com AIO
para ganhar só 3% de performance.

Seja AIO ou multiplexação, só tem vantagem sobre thread-per-socket se for para lidar com um número muito grande de
conecções. Nos outros casos a diferença vai ser irrisória entre os dois modelos.
 

> Minha experiência foi ao implementar um servidor de SMTP. A diferença do
> custo para implementár e dar manutenção usando thread-per-socket e proactor
> não se justifica, sai mais barato comprar mais hardware.

Sua experiencia foi certamente diferente da minha.

[snip]

> > Mesmo nao tendo requisto de pouca memória, desperdiça-la em 100
> > threads é na minha opiniao um pouco irresponsável.
>
> Irresponsável? Memória é estupidamente barato hoje em dia. 100 thread vão te
> custar uns 200Mb de ram no pior caso - que por sinal significa que o
> programa tem muitos outros problemas para usar ativamente 2Mb de stack!
> Ainda mais hoje que servidores com 4Gb de ram é perfeitamente normal.

4GB recebendo ou enviando mensagens de 200MB é pouquinho ;).
Esse argumento é o mesmo que os javeiros usam. E mesmo assim
usar programas java me incomoda muito. Só nao incomoda o desenvolvedor
eu presumo.


Mensagens de 200Mb? Quem falou em mensagens? Eu falei que o custo de subir 100 threads
não passa de 200Mb no total.

Esse argumento de que o que importante é performance é uma das coisas que mais me
incomoda no povo que usa C++, parece que não existe outra bandeira para defender. Eu acredito
que todo programador tem que ser pragmático, tem que ser da maneira que melhor atender os
propósitos daquilo que estiver fazendo. Trocar performance por entregar mais cedo é o
exemplo mais comum disso. Tem que aceitar que usar sua linguagem preferida pode não
ser a ferramenta ideal para resolver o problema em questão.





[]'s
Rodrigo

Psycho Mantys

unread,
Apr 10, 2008, 6:16:12 PM4/10/08
to ccppb...@googlegroups.com
################################################################################

Hugo Parente Lima say:

Com QThread talvez usando QThread::currentThreadId() dê para fazer algo não
portável... mas antes você tem que fazer um trabalho de mineração no código
fonte da Qt para saber o que tem no danado do Qt::HANDLE que esse método
retorna na plataforma que vc estiver usando... se a pthreads usar alguma
variável de ambiente para saber o tamanho da pilha que vai usar seria melhor
ainda.

####

 hugo, int pthread_attr_getstacksize (__const pthread_attr_t *__restrict __attr, size_t *__restrict __stacksize); seria oque voce quer? Tambem a uma macro(eu acho): PTHREAD_STACK_MIN que diz o tamanho minimo da stack. Viajei ou e isso?

:D

Hugo Parente Lima

unread,
Apr 10, 2008, 6:38:13 PM4/10/08
to ccppb...@googlegroups.com
On Thursday 10 April 2008 19:16:12 Psycho Mantys wrote:
> ###########################################################################

>#####
>
> Hugo Parente Lima say:
>
> Com QThread talvez usando QThread::currentThreadId() dê para fazer algo não
> portável... mas antes você tem que fazer um trabalho de mineração no código
> fonte da Qt para saber o que tem no danado do Qt::HANDLE que esse método
> retorna na plataforma que vc estiver usando... se a pthreads usar alguma
> variável de ambiente para saber o tamanho da pilha que vai usar seria
> melhor ainda.
>
> ####
>
> hugo, int pthread_attr_getstacksize (__const pthread_attr_t *__restrict
> __attr, size_t *__restrict __stacksize); seria oque voce quer? Tambem a uma
> macro(eu acho): PTHREAD_STACK_MIN que diz o tamanho minimo da stack. Viajei
> ou e isso?
>
> :D

Falei no código fonte da QThread, não no cabeçalho da pthread, a QThread (no
Linux) é só um wrapper para a pthread, por isso esse método
QThread::currentThreadId() pode ser que retorne um handler ou coisa parecida
que você possa utilizar nas funções da pthread... eu sempre usei apenas
bibliotecas de thread mais alto nível e com interfaces bonitinhas for
dummies, por isso não sei se posso ajudar em qualquer coisa que lide
diretamente com a pthread... visto que eu só a utilizei indiretamente (via
QThread por exemplo).

signature.asc

Amanda Cristina

unread,
Apr 10, 2008, 9:28:36 PM4/10/08
to ccppb...@googlegroups.com
Fernando,
 
      Será que você poderia postar um passo-a-passo de como você vez para instalar o Boost::Thread? Pergunto, pois isto é algo que já tentei algumas vezes e não consegui, sempre dá um erro que a libxxxthreadxxGDxxnnn não pode ser encontrada e eu já segui vários cookbooks e how to´s de como instalar e não consegui.
 
      Do resto, sempre tive sucesso e alegria com o Boost exceto pelo multi-threading que é algo que já me tirou do sério e eu não consegui utilizar até hoje.
 
      IMHO, sobre o Boost::ASIO eu concordo com o Kumpera, ele é um recurso interessante mas  o modelo thread-per-socket é sempre mais saudável e oferece desempenho melhor, mas quando os recursos do hardware "carecem" o software padece e aí lançar mão do ASIO pode ser uma grande sacada.
 
[ ]s
 
Amanda

Felipe Magno de Almeida

unread,
Apr 11, 2008, 12:41:52 AM4/11/08
to ccppb...@googlegroups.com
2008/4/10 Rodrigo Kumpera <kum...@gmail.com>:
>

[snip]

> Me corrija se estiver errado, mas mesmo usando AIO você tem os mesmos


> problemas de multi-threading se quiser escalar para múltiplos cores.

Sim, certamente. Mas para programas networking a utlização de CPU será minima.
Muitas vezes nem necessitando utilizar mais de um core.

> Porém
> concordo contigo, escrever programas multi-threaded com C ou C++ é um raro
> tipo de tortura que deve ser evitado.

Lol.

> Certamente usar AIO com uma FSM vai
> ser mais escalável, porém em alguns casos isso é otimizar as partes que não
> são o hotspot do programa.

Acredito que isto nao é o caso de ums servidor. Se alguém precisa de
mais de 350 threads
acredito que seja para manter 350 jobs diferentes e simlutâneos. AIO
beneficiaria *muito*
este caso de uso me parece.

> Ser 2x mais eficiente em 10% do programa só vai
> tornar o programa 5% mais rápido.

Com certeza.

> Como falei, o importante é avaliar a
> necessidade e os requisitos a serem implementados.

Concordo. Mas nao consigo ver como uma aplicação pode se beneficiar de
350 threads de forma alguma.

> Quer um exemplo? Qualquer solução com AIO tem latência maior e eficiência
> menor que thread-per-socket. Os SOs modernos não conseguem fazer
> zero-copy-txer com aio assíncrona ou não bloqueante na maioria dos casos.
> Isso, claro, se tivermos menos sockets que cores. ;)

Nem conseguem fazer zero-copy pra bloqueante. É necessário usar mmap, AFAIK.

[snip]

> Você parou para fazer as contas? Provavelmente não. Vou umar o linux como
> exemplo.
> Usando uma thread por socket, cada uma usar 1 timeslice por comando, serão 3
> context
> switches por email enviado (MAIL TO, RCPT TO e DATA). Um context switch no
> linux

Acho que sua conta está errada.
Para cada email é necessário EHLO, MAIL FROM, RCPT TO, DATA, leitura
dos dados do HD,
os próprios dados, muitas vezes sem sao necessários mais de um envio
para os dados
por falta de buffers, o ponto CRLF.CRLF e opcionalmente o QUIT.

Isso sao 7 context switches por mensagem.

> usa aproximadamente 2500 ciclos. Para um sistema que aceita mil emails por
> segundo,

2500*7 = 17500.
Com 17500 ciclos o custo de receber ou enviar o email está em maior
parte nos context switches.
Podemos ter assim a CPU como limitante, o que é completamente
desnecessário se fosse
utilizado um design melhor desde o início.
É por isso que programas feitos com AIO costumam ter utilizacao de CPU
minuscula, muitas
vezes imperceptível. Isto pra mim acrescenta em muito na qualidade do software.

> isso são 1000 * 2500 * 3, ou 7.5Mhz. Com uma CPU de 2.4Ghz isso são 0.3% de
> economia.
>
> Ainda assim, supondo que vamos ter melhor afinidade de cache e isso vai
> aumentar em dez vezes
> o ganho, são só 3%! Desculpa, mas todo tem algo melhor para fazer que ficar
> se esfolando com AIO
> para ganhar só 3% de performance.

Com 350 threads acredito que o cache thrashing vai ser insano. E bem possivel
que ao inves de 10 vezes, chegue a 100 vezes pior. E nao para o codigo
de context switch.

> Seja AIO ou multiplexação, só tem vantagem sobre thread-per-socket se for
> para lidar com um número muito grande de
> conecções. Nos outros casos a diferença vai ser irrisória entre os dois
> modelos.

Que acredito ser o caso de qualquer um querendo utilizar mais de 350 threads.

> Mensagens de 200Mb? Quem falou em mensagens? Eu falei que o custo de subir
> 100 threads
> não passa de 200Mb no total.

O que eu quis dizer é que você estava presumindo uma utilização minima
de memória para o resto do software, o que
pode nao ser verdade. Isto ocorre se você estiver precisando processar
mensagens grandes in-memory, como por exemplo
com várias mensagens de 200MB.
Porém, 200MB de memória é bastante memória pra ser desperdiçada mesmo
em uma máquina de 4GB.
E utilizando-a somente pra ocupar espaço *é* puro desperdício. Se
estivesse utilizando com algo útil
eu nao discutiria, mas ter 200MB pra só ficar lá sentado esperando é
uma desconsideração com o usuário, IMHO.
Se todo software decidisse fazer isto, eu nao conseguiria rodar nada
nem na minha máquina de 8GB de memória.

> Esse argumento de que o que importante é performance é uma das coisas que
> mais me
> incomoda no povo que usa C++, parece que não existe outra bandeira para
> defender. Eu acredito
> que todo programador tem que ser pragmático, tem que ser da maneira que
> melhor atender os
> propósitos daquilo que estiver fazendo.

Acredito que você me interpretou mal. Nunca irei defender a utilizacao
de asynchronous
IO em um cliente de FTP de console por exemplo. Mas utilizar mais de 350 threads
em um processo é pra mim um *forte* indicativo de que o projeto está
*mal feito*.

> Trocar performance por entregar mais
> cedo é o
> exemplo mais comum disso. Tem que aceitar que usar sua linguagem preferida
> pode não
> ser a ferramenta ideal para resolver o problema em questão.

Dúvido que o Fernando considere C++ uma linguagem inapropriada, se achasse
ele provavelmente nao teria enviado uma mensagem para este grupo.

> []'s
> Rodrigo

Thiago Adams

unread,
Apr 11, 2008, 5:07:26 AM4/11/08
to ccppbrasil


On Apr 11, 2:28 am, "Amanda Cristina" <amazo...@gmail.com> wrote:
>       Será que você poderia postar um passo-a-passo de como você vez para
> instalar o Boost::Thread?

Procura por "[Boost-announce] Boost 1.35.0 released" aqui na lista.
Lá tem a resposta de como compilar. (Fiz isso esta semana)
Se você tiver mais dúvidas acho que pode criar um tópico separado.

Felipe Magno de Almeida

unread,
Apr 11, 2008, 5:12:36 AM4/11/08
to ccppb...@googlegroups.com
2008/4/10 Amanda Cristina <amaz...@gmail.com>:
> Fernando,

[snip]

> IMHO, sobre o Boost::ASIO eu concordo com o Kumpera, ele é um recurso
> interessante

Boost.Asio é uma biblioteca de I/O. Só possui networking até agora,
mas serve tanto
pra asynchronous IO quanto synchronous IO.

> mas o modelo thread-per-socket é sempre mais saudável e
> oferece desempenho melhor,

Eu discordo quanto a parte saudável, o IO é inerentemente assíncrono.
Mas concordo que
nao é tão straightforward de inicio este modelo. Mas a biblioteca asio
tenta tornar o uso
de asynchronous IO tao simples quanto synchronous IO. Um pouco mais
prolixo porém.

> mas quando os recursos do hardware "carecem" o
> software padece e aí lançar mão do ASIO pode ser uma grande sacada.

É.

> [ ]s
>
> Amanda

Pedro Lamarão

unread,
Apr 11, 2008, 1:08:19 PM4/11/08
to ccppbrasil
On 10 abr, 16:17, "Fernando Gomes" <ferg...@googlemail.com> wrote:
> Caros,
>
> Pode ser um pouco off-topic - pois acho eu que a questão está
> relacionado ao OS Scheduller - mas após fazer algumas experiências com um
> código portável entre FreeBSD, Linux e Win32 onde fiz códigos com QThreads,
> Pthreads, Boost Thread e outro com wxThread e numa mesma máquina tive
> resultados bastantes parecidos...
>
> 350 threads no Linux Ubuntu e OpenSuse
> 1800 threads no Windows XP
> 3600 threads no FreeBSD

Cientificamente, os seus resultados estão apresentados de forma
incompleta.

O que significa "1800 threads no Windows XP"?

O que você está medindo?

Onde está o código-fonte do seu teste?

--
P.

Carlos Eduardo

unread,
Apr 17, 2008, 11:10:22 AM4/17/08
to ccppb...@googlegroups.com
Srs,

     No melhor estilo  trash movie re-animator, já que o Fernando Gomes levantou a bola, por favor alguém sabe dizer-me o porque por mais que eu coloque qualquer valor em QThread::setStackSize() a quantidade de threads por processo sempre fica a mesma? Detalhe, fazendo um código similar em Ruby alterando o valor de stacksize por thread para 16384 eu consigo abrir 40.000 threads na mesma instalação do Fedora que eu nunca consigo sair de 380 threads com o C++/QT

#include <QtCore>
#include <QThread>
#include <QList>
#include <iostream>


class Tester : public QThread {
      public:
          void run();
          };

   void Tester::run(){
       forever{
           sleep(100);
       };
   };

int main()
{
    int size = 0;
    while(true) {
        QList<Tester*> segmentos;
        Tester *thread = new Tester();
        segmentos.append(thread);

        thread->setStackSize(1024*16);
        thread->start();
        std::cout << "Threads:" << ++size << std::endl;
        if (!thread->isRunning() ) {
           
            break;
            }
        }

}

    Desde já grato.

Cadú

Em 11/04/08, Pedro Lamarão <pedro....@gmail.com> escreveu:

Marco Aurélio

unread,
Apr 17, 2008, 12:55:50 PM4/17/08
to ccppb...@googlegroups.com
Cadú,

    Não sei resolver o seu problema das threads, também sou padawan na arte do C++, mas o teu código eu escreveria um pouco diferente, usando do while e sem aquela variável contadora que vc colocou utilizando o método size da QList, como no código abaixo que não sei se está compilando:

/*------------------------------------[cute_here]------------------------------------*/

int main()
{
    QList<Tester*> segmentos;
    bool Running = true;

    do {


        Tester *thread = new Tester();

        segmentos.append(thread);

        thread->setStackSize(1024*16);
        thread->start();
        Running = thread->isRunning();

        std::cout << "Threads:" << segmentos.size() << std::endl;
    } while( Running );

}

/*------------------------------------[cute_here]------------------------------------*/

[]s

Marinho


Em 17/04/08, Carlos Eduardo <cle...@gmail.com> escreveu:

Carlos Eduardo

unread,
Apr 20, 2008, 12:02:45 PM4/20/08
to ccppb...@googlegroups.com
Pyro,

     Obrigado! Sinceramente eu estava mais preocupado com as threads do que com o estilo, assim ficou melhor!

Pessoal,

     Alguém sabe dizer-me porque o que está ocorrendo com QThread no meu código? Pq eu não consigo alocar mais threads mesmo alterando o valor de do Stack Size, que em Ruby e em C++/pthreads funciona perfeitamente?

[]s

Cadú
    

Em 17/04/08, Marco Aurélio <pyrot...@googlemail.com> escreveu:

Fernando Gomes

unread,
Apr 20, 2008, 12:42:18 PM4/20/08
to ccppb...@googlegroups.com
Cadú,

      Não pense que estou sendo omisso, eu também não descobri como fazer isto com QThread. Com pthread foi tranquilo, tive sucesso, mas com o QT...

[]s

./Fer -G0

Em 20/04/08, Carlos Eduardo <cle...@gmail.com> escreveu:

Hugo Parente Lima

unread,
Apr 20, 2008, 3:53:40 PM4/20/08
to ccppb...@googlegroups.com
Também não faço ideia, mas tenta perguntar isso em #kde-devel ou
-#kde-brasil (ou é #kde-br, não lembro) no irc (freenode) que
provavelmente alguém saberá responder... até pq um povo que trabalha
na trolltech costuma ficar nesses canais tb.

2008/4/20 Fernando Gomes <fer...@googlemail.com>:

--

Basilio_Miranda

unread,
Apr 22, 2008, 4:05:35 PM4/22/08
to ccppbrasil

Em 20/04/08, Carlos Eduardo <cles...@gmail.com> escreveu:
[ Alguém sabe dizer-me porque o que está ocorrendo com QThread no
meu
código? Pq eu não consigo alocar mais threads mesmo alterando o valor
de do
Stack Size,(...)
]

Inicialmente pensei que essa era uma questão puramente recreativa.
Mas, depois, recebi um e-mail particular, solicitando ajuda sobre
isso.
Ao que parece, pensa-se, seriamente, em criar tal quantidade de
threads simultaneamente em um mesmo processo.
Não consegui enxergar o uso. Em todo caso, nunca se sabe...

Cito alguns exemplos, em uma mesma máquina, com Windows XP e Ubuntu -
sem Qt e com Qt:

a) WINDOWS:

a.1 - Usando a API win32 com Visual C++, obtive 2031 threads
simultâneos.
Alterando os valores da pilha podemos atingir bem mais (no Windows XP/
2003, usando o flag STACK_SIZE_PARAM_IS_A_RESERVATION em
"CreateThread").
Assim, o limite para a quantidade de threads está na memória
disponível para um processo.

a.2 - Usando o porte de gcc (mingw) para Windows (sem Qt) obtive 1015
threads.

a.3 - Usando Qt (com o mesmo porte de gcc) obtive 1006 threads. Qt
cria suas próprias threads, então a diferença é desprezível com
relação a "a.2".

Logo, em "a.2" e "a.3", o que parece determinar a quantidade de
threads é a mingw.
Observar que mingw tem suas prórias libs para Win32 (inclusive
kernel32) e são elas que o gcc usa.
Embora, em execução, seja usada a própria Win32(dlls), seria preciso
saber o que fazem as libs de mingw quanto a isso. Não vi nada
documentado, embora não tenha procurado muito.

b) LINUX:

Em princípio, poderia existir um limite, determinado por
PTHREAD_THREADS_MAX.
Mas normalmente esse valor NÃO É usado, não havendo assim um limite
absoluto, restando portanto apenas o limite de memória (como no
Windows).
Podemos saber disso chamando
ulimit -a

b.1 - Então, usando diretamente pthreads, obtive cerca de 15.000
threads;

b.2 - usando Qt obtive 511 threads.

Qual a razão disso?

Qt abre, para cada thread, uma conexão ao sistema para capturar
eventos, através de pipes, e com isso cria descritores de arquivos. E
existe uma quantidade máxima para descritores de arquivos no sistema.
Então, se inspecionarmos as mensagens de "qWarning" veremos que ao
tentar criar o thread #512 temos a seguinte mensagem:

[ "QEventDispatcherUNIXPrivate(): Unable to create thread pipe: Too
many open files" ]

Isso ocorre do seguinte modo:

Qthread::start()
{
// ....
pthread_create(&d->thread_id, &attr,
QThreadPrivate::start, // "START ROUTINE"
this);
//
// observar acima que a "START ROUTINE" do thread é a função
estática "QThreadPrivate::start"
}

// "Start routine" de qualquer thread em Qt::
void * QThreadPrivate::start(void * arg)
{
QThread *thr = reinterpret_cast<QThread *>(arg);
///....
createEventDispatcher(data); // <<<< cria um objeto para capturar
eventos do SO
///....
thr->run(); // aqui o nosso thread efetivamente inicia, na
redefinição desta virtual em uma derivada.
}

A chamada, acima, a "createEventDispatcher(data)", irá criar um objeto
do tipo QEventDispatcherUNIXPrivate e sua construtora fará o
seguinte:

QEventDispatcherUNIXPrivate::QEventDispatcherUNIXPrivate()
{
extern Qt::HANDLE qt_application_thread_id;
mainThread = (QThread::currentThreadId() ==
qt_application_thread_id);

// initialize the common parts of the event loop
pipe(thread_pipe);
fcntl(thread_pipe[0], F_SETFD, FD_CLOEXEC);
fcntl(thread_pipe[1], F_SETFD, FD_CLOEXEC);
fcntl(thread_pipe[0], F_SETFL, fcntl(thread_pipe[0], F_GETFL) |
O_NONBLOCK);
fcntl(thread_pipe[1], F_SETFL, fcntl(thread_pipe[1], F_GETFL) |
O_NONBLOCK);

sn_highest = -1;

interrupt = false;
}

CONCLUSÃO:
Passamos a ter um limite. Não de threads, mas de descritores de
arquivos.

Basilio Miranda
Reply all
Reply to author
Forward
0 new messages