512 Threads rodando simultaneamente!!!

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

yugi386
Usuário Nível 2
Usuário Nível 2
Mensagens: 82
Registrado em: 24 Jul 2008 10:36
Localização: Minas Gerais

512 Threads rodando simultaneamente!!!

Mensagem por yugi386 »

Saudações!

Queria testar até onde ia a capacidade do meu note Intel core i5 - 3210m, 2.5GHZ.
Aí bolei este código em harbour para criar 512 Threads e executá-las simultaneamente. Este processador tem 2 núcleos porém 4 Threads.

O teste trata-se de leitura e escrita frenética em uma tabela com 100.000 registros. Simula 512 usuários escrevendo simultaneamente na tabela DBF.
O uso do processador chega rapidamente a 100% mais não trava.

Também testei o mesmo código rodando em 4 abas separadas do terminal do linux (executando 2048 Threads!!!). Neste caso o processamento ficou lento porque cada núcleo do processador precisa suportar 512 processos simultâneos, além do fato dos supostos 2048 usuários estarem usando a mesma tabela ao mesmo tempo e escrevendo cada um 100.000 nesta mesma tabela.

Eis o código:

Código: Selecionar todos

#include "hbthread.ch"

	DBSETDRIVER("DBFCDX")
	REQUEST HB_LANG_PT
	REQUEST HB_CODEPAGE_UTF8EX
	HB_LANGSELECT( 'PT' )
	HB_CDPSELECT( "UTF8EX" )	


func main()
	memvar contador, contarT, controla
	private ct:=1, numeroThreads := 512, numreg:= 100000, tam:=0

	contarT := 0	// gerencia o numero de threads
	controla:=numeroThreads	// obriga todas as threads a rodarem ao mesmo tempo

	setmode(32,125)

	contador := array(numeroThreads)
	for ct:= 1 to len(contador)
		contador[ct] := 0	
	next

	cls
	if !file("banco.dbf")
		dbcriar()
	endif

	tam := len(contador)
	cls
	
	timeINI = time()

	// disparando as Threads
	for ct := 1 to len(contador)
		nNovaThread := hb_ThreadStart(  HB_THREAD_INHERIT_MEMVARS, @trocar() )
		do while contador[ct] == 0
			inkey(0.01)
		enddo

		linha := 0
		coluna := 0
		for ct2 := 1 to tam
			@ linha,coluna say str(contador[ct2],6)
			linha = linha + 1
	
			if linha > 31
				linha:= 0
				coluna := coluna + 7
			endif
		next

	next

	do while.t.
		linha := 0
		coluna := 0

		for ct := 1 to tam
			@ linha,coluna say str(contador[ct],6)
			linha = linha + 1
	
			if linha > 31
				linha:= 0
				coluna := coluna + 7
			endif
		next

		if contarT >= tam .or. verifica(contador,numreg) == numreg
			exit
		endif

		@ linha,coluna say str(contarT,4) + " finalizadas!"

	enddo

	timeFIM = time()

	cls
	use banco shared new
	go top
	alert("INICIO..: "+ timeINI + chr(13) + chr(10) + " FIM..: " + timeFIM)
	@ 00,01 say "TECLA ESC PARA SAIR!"
	browse(01,01,24,79)
    close all

return nil

// =========================================================
function dbcriar()

	aDbf := {}
	AADD(aDbf, { "c1", "C", 10, 0 })
	AADD(aDbf, { "c2", "C", 10, 0 })
	AADD(aDbf, { "c3", "C", 10, 0 })
	AADD(aDbf, { "n1", "N", 10, 0 })
	AADD(aDbf, { "n2", "N", 10, 0 })
	AADD(aDbf, { "n3", "N", 10, 0 })

	DBCREATE("banco", aDbf,, .T.)

	? time()

	for ct:= 1 to numreg
		dbAppend()
		replace c1 with "0"
		replace c2 with "1"
		replace c3 with "2"
		replace n1 with seconds()
		replace n2 with seconds()
		replace n3 with seconds()
	next

	dbCloseArea()
	? time()

return nil

// =========================================================
function trocar()
local ct := 0, tam := len(contador)

	for ct := 1 to tam
		if contador[ct] == 0
			ponteiro := ct
			exit
		endif
	next

	controla = controla - 1

	use banco shared new
	if neterr()
		cls
		? "Erro de abertura de arquivo DBF"
		quit
	endif
	go top

	do while.not.eof()
		do while rlock() == .f.
		enddo

		replace c1 with alltrim(str( int( (val(c1) + val(strtran(time(),":","")) * int(hb_random(1000000))) % 1000000000 )))
		replace c2 with alltrim(str(int((val(c2) + val(strtran(time(),":","")) * int(hb_random(1000000))) % 1000000000 )))
		replace c3 with alltrim(str(int((val(c3) + val(strtran(time(),":","")) * int(hb_random(1000000))) % 1000000000 )))
		replace n1 with (n1 * seconds() + int(hb_random(1000000))) % 1000000000
		replace n2 with (n2 * seconds() + int(hb_random(1000000))) % 1000000000
		replace n3 with (n3 * seconds() + int(hb_random(1000000))) % 1000000000

		unlock

		contador[ponteiro] := contador[ponteiro] + 1

		do while controla > 0
			inkey(0.1)
		enddo

		skip
	enddo

	dbCloseArea()

	contarT := contarT + 1
return
// --------------------------------------------------------
function verifica(vetor,total)
	local ret := 0, tam:=len(vetor), ct:=0

	for ct:= 1 to tam
		if vetor[ct] == total
			++ret
		endif
	next

return ret

att,

Yugi
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

512 Threads rodando simultaneamente!!!

Mensagem por janio »

Nossa cara, Massa!

Seu codigo eh muito complexo para o meu conhecimento simplório, mas vou compilar aqui o seu exemplo e ver o que acontece!

:{

Janio
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

512 Threads rodando simultaneamente!!!

Mensagem por janio »

Perae!

Dxa so entender uma coisa: Uma thread so inicia quando a anterior termina, não eh isso? Se assim for não seria "512 usuarios fazendo gravações simultaneas na mesma tabela" pq justamente um so começa a gravar qndo o outro termina.

To certo?
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
yugi386
Usuário Nível 2
Usuário Nível 2
Mensagens: 82
Registrado em: 24 Jul 2008 10:36
Localização: Minas Gerais

512 Threads rodando simultaneamente!!!

Mensagem por yugi386 »

Saudações!

O código força todas as 512 threads a fazerem o "trabalho pesado" começando ao mesmo tempo.
É por isto que existe o carregamento dos 512 valores "1" .
Naturalmente, ao gravar na tabela, é preciso alterar um registro de cada vez, mas muitos registros ao mesmo tempo.
Se trata portanto de simular o uso de 512 usuários fazendo 100.000 alterações em uma única tabela ao mesmo tempo (mas não no mesmo registro evidentemente). É preciso respeitar os rlocks() da vida!!!
Veja que o código mostra na tela quantos registros foram alterados por cada usuário e quantas threads foram finalizadas.

abraço,

Yugi386
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

512 Threads rodando simultaneamente!!!

Mensagem por janio »

Vc tem razao! Uma thread não fica amarrada ao processo anterior. Na verdade, qndo uma thread inicia a chibata come por la e o restante do codigo continua...

Processamento enorme! Processador foi a mil kkkk

46 minutos num notebook Core i5, 8gb ram

Janio
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

512 Threads rodando simultaneamente!!!

Mensagem por JoséQuintas »

Mas cuidado.
Isso pode fritar o processador, se tiver problemas de cooler.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

512 Threads rodando simultaneamente!!!

Mensagem por JoséQuintas »

Fiz pequenas alterações no fonte, por curiosidade, e a diferença foi estrondosa: uma janela pra cada thread.
Mas não deu tempo de ver se realmente executou todas as threads.
Usei GTWVG pra usar várias janelas.
Um detalhe é que ao usar multijanela, os inkey() de cada thread se tornam independentes (pois cada janela tem seu mouse/teclado).
E apesar da máquina aparentemente congelar (muitas threads e janelas), não chegou a 100% de CPU.
No final, o DBF continha 100.000 registros, e demorou 30 segundos pra terminar.

Código: Selecionar todos

// No início
#include "hbgtinfo.ch"

// No módulo principal
CLS

// Na rotina a executar
     hb_gtReload( hb_GTInfo( HB_GTI_VERSION ) )
   CLS

// pra compilar
hbmk2 test -mt gtwvg.hbc
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

512 Threads rodando simultaneamente!!!

Mensagem por JoséQuintas »

Jânio, se puder testar pra comparar com o teste anterior, está aí o fonte alterado pra facilitar.
Compile conforme indicado: hbmk2 test -mt gtwvg.hbc
No final, o DBF fica com pouco mais de 6MB, com os 100.000 registros.

É interessante ver que uma janela pra cada processo faz muita diferença.
Se fosse o caso, seria só deixar com janela invisível.

Apenas um chute para o motivo: provavelmente o que fazia demorar era um inkey() esperar o outro, e o mesmo pra atualizar a tela.
E já em janelas independentes, cada processo faz sua parte sem depender do outro processo.

Jä no fonte original, interrompi pelo gerenciador de tarefas, porque 100% de CPU pode significar ferver processador.
Então não tenho o tempo sem a alteração, exceto a informação do Jânio de 46 minutos.
De 46 minutos pra 30 segundos, melhor o Jânio testar no mesmo computador, porque a diferença tá grande.
Anexos
test.prg
(3.59 KiB) Baixado 128 vezes
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar do usuário
janio
Colaborador
Colaborador
Mensagens: 1846
Registrado em: 06 Jul 2004 07:43
Localização: UBAJARA - CE

512 Threads rodando simultaneamente!!!

Mensagem por janio »

Quintas,

Compilei o seu exemplo sem acrescimo de nenhum virgula e deixei rodando por 5 minutos (fiquei com medo de torrar meu processador kkk)

- Apenas uma janela foi aberta;
- Nos 5 minutos q rotina rodou, cada thread processou cerca de 15mil registros, dos 100mil previstos

Nao deixei rodando ate o final, mas ta longe dos 30 segundos q vc mencionou!

Janio
fui...
e-mail:janioaguiar@yahoo.com.br
msn: janio_aguiar@hotmail.com
xHarbour1.2.1/Harbour3.2 + wvg + hwgui + Mediator + MySql
yugi386
Usuário Nível 2
Usuário Nível 2
Mensagens: 82
Registrado em: 24 Jul 2008 10:36
Localização: Minas Gerais

512 Threads rodando simultaneamente!!!

Mensagem por yugi386 »

Saudações!

Prezados amigos,

No código original em modo console, numa só janela, utilizando um processador intel core i5 - 3210M (4 núcleos) com 6GB de RAM, embora no processamento o uso da memória fica abaixo de 1 GB, o tempo de processamento quase exclusivo é de 11 minutos e 41 segundos.

Quando digo processamento quase exclusivo significa sem utilizar outro programa a não ser o sistema operacional. No meu caso eu uso linux lubuntu 14.10. Acredito que no windows pode haver tempo discrepante porque os programas residentes (antivírus, etc...) podem gastar alguns recursos da máquina.

Quanto ao tipo de processamento do código tenho a dizer duas coisas:

1) Quando faço com que as 512 threads comecem ao mesmo tempo existe o problema de aguardar que o registro esteja livre (liberar o rlock()) porque a escrita da tabela é sequencial, ou seja, começa no registro 1 e vai até 100.000. São 512 processos concorrendo pelo uso exclusivo do registro e isto faz uma grande diferença no processamento principalmente porque utilizamos uma tabela DBF (com um SGDB o resultado pode ser diferente (?)).

2) Caso você libere a thread imediatamente a disputa pelos rlock() fica um pouco menos agressiva porque a thread 1 trava, grava e libera o registro 1, depois trava, grava e libera o registro 2, e assim por diante. Quando a thread 2 iniciar, provavelmente o registro 1 estará liberado e assim sucessivamente para as outras threads (evidentemente isto não é uma regra) . A luta pelo registro liberado fica muito menos agressiva do que se você iniciar as 512 threads ao mesmo tempo, conforme o código original.

O teste feito pelo amigo José Quintas parece não ter sido completado no tempo informado porque apesar da tabela ter 100.000 registros ela foi criada assim, com esta quantidade de registros. As modificações nos registros que fazem o processamento não são de inclusão e sim de alteração de registros. O fato da tabela ter 100.000 registros no final do processo não garante que as 512 threads tenham terminado com sucesso.


abs,

Yugi
Avatar do usuário
JoséQuintas
Administrador
Administrador
Mensagens: 20267
Registrado em: 26 Fev 2007 11:59
Localização: São Paulo-SP

512 Threads rodando simultaneamente!!!

Mensagem por JoséQuintas »

Só consegui ver o real motivo depois que acrescentei minha errorsys.prg
Ultrapassou o limite de janelas da GTWVG.

Código: Selecionar todos

Application Internal Error - d:\temp\test.exe
Terminated at: 2015-04-26 13:36:38
Unrecoverable error 10001: Maximum number of WVG windows reached, cannot create another one
Called from HB_GTRELOAD(0)
Called from TROCAR(130)
------------------------------------------------------------------------
Tive que reduzir pra somente 250 threads.
Também deixei as janelas das threads invisíveis, pra facilitar ver a primeira tela.
E se deixar a janela principal fora de foco, o processamento fica mais rápido, porque não atualiza instantâneo.
.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg mt, fivewin 25.04, multithread, dbfcdx, MySQL, ADOClass, PDFClass, SefazClass, (hwgui mt), (hmg3), (hmg extended), (oohg), PNotepad, ASP, stored procedure, stored function, Linux (Flagship/harbour 3.2)
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Responder