Página 1 de 2

CPU 100% com o HARBOUR

Enviado: 29 Abr 2010 11:46
por levis_me
Srs., Bom Dia!
Desenvolvi um programinha para gerar um arquivo .txt com uma sequencia de numeração. Esse arquivo .txt pode ter de 100 mil a mais de 1 milhão de numeros. Até aqui blz...o programa funciona corretamente.
O meu problema é q quando solicitado para gerar com uma qtde grande de numeros o CPU do PC fica em 100% e o programa parece travado, mas não está, esta executando. Até a régua de processamento fica travada. O que pode ser isso? Como posso resolver?

Abraço.

Re: CPU 100% com o HARBOUR

Enviado: 29 Abr 2010 13:17
por rochinha
Amiguinho,

isto vai depender de como sua rotina foi elaborada.

O código da mesma, se apresentado aqui no forum nos daria a informação mais exata para não termos de partir de suposições.

O processamento esta na lua porque voce esta escrevendo o arquivo enquanto gera.
O processamento pode produzir muita leitura e escrita enquanto é gerado.
O processamento é atrasado pelas rotinas que mostram o processamento sendo efetuado.

Solução:

Gerar estes numeros e preencher um vetor e depois descarregar este vetor de uma vez num arquivo.
Gerar a numeração gravando registros em um DBF depois gerar o arquivo TXT por SDF.
Gerar os numeros e salvá-los no arquivo TXT a cada 10%.

Em suma:

- Sem visualizar a rotina não podemos dar uma solução prática.
- Sem saber o objetivo da rotina ficamos sem saber se já existe alguma idéia pronta.

Re: CPU 100% com o HARBOUR

Enviado: 30 Abr 2010 09:39
por levis_me
Rochinha,

O objetivo da rotinha é gerar o código verificador da numeração sequencial e gravar o numero + o verificar em .txt

Como vc podera ver abaixo, ja faço a a gravação inicialmente em DBF e somente depois gravo em TXT e mesmo enquanto esta gerando o DBF o CPU fica em 100%.
Fiz teste também com Array, mas não mudou nada.

Pode ser a rotina mesmo que necessite de processamento, devido aos cálculos neh.
Mas de qualquer forma, segue a rotina abaixo para que vcs possam visualiza-la:

Código: Selecionar todos

FUNCTION 2Col()
Peso:='8765432'       
USE PRV
ZAP
for j=0 to Qt
			a:=0
	      If Nm = 10000000
	      	Nm := 5000000
      	Endif
      	Num:=alltrim(strzero(nm,7))
	      for t=1 to 8
	         sm1:=val(subs(num,t,1)) * val(subs(Peso,t,1))
	         a+=sm1
	      next
	      nm++
	      dg:=mod(a,11)
		   dg2:=11-dg
		     	if j = qt1
		     		dbgotop()
	    		endif
		 		if j < qt1
            	PRV->(dbappend())
		     		PRV->campo1:=num+substr(Strzero(dg2,2),2,1)
	  			else
	    			PRV->campo2:=num+substr(Strzero(dg2,2),2,1)
	    			skip
	  			endif
	  			Progress1() 
		next
		Set alter on                             
	   Set alter to '2Col.txt'
	   dbgotop()
		While !Eof()
		 	? substr(campo1,1,8)+substr(campo2,1,8)				 	
		   skip
			Progress2()
		Enddo
		set alter to
		Count to nREG
		Digito.Label_1.Value:="Arquivo Gerado" + STR(nREG)
CLOSE
RETURN NiL

Abraço.

CPU 100% com o HARBOUR

Enviado: 30 Abr 2010 11:34
por Pablo César
Levis, não esqueça de colocar o seu código sempre entre tags (code), eu ja corrigí pra você.

Eu acho que pode haver dois agravantes aí.

1. Tem necessidade de gravar em dbf ? Se puder evitar melhor, faça um contador, e grave diretamente no arquivo TXT em baixo nível.
2. As funções progress (1 e 2) acho que deve exibir em tela uma barra de progresso (como você mencionou), isto pode estar contribuindo seriamente a velocidade de execução do seu app., pois tendo a necessidade de mostrar em tela faz acesso IO (evite se puder para ganhar mais desempenho)

Re: CPU 100% com o HARBOUR

Enviado: 30 Abr 2010 12:36
por rochinha
Amiguinho,

Então o problema pode estar na geração do arquivo.

Voce esta usando ? ... passe a usar função de baixo nivel como Fcreate(), FWrite e FClose() elas terão um consumo muito menor para isto.

Consulte mais informações de como usá-las.

Mude:

Código: Selecionar todos

...
      next
      Set alter on                             
      Set alter to '2Col.txt'
      dbgotop()
      While !Eof()
          ? substr(campo1,1,8)+substr(campo2,1,8)                
         skip
         Progress2()
      Enddo
      set alter to
      Count to nREG
...
Por:

Código: Selecionar todos

...
      next
      ret_line := "chr(13)+chr(10)" // Set alter on                             
      errhandle := FCREATE('2Col.txt') // Set alter to '2Col.txt'
      dbgotop()
      do While !Eof()
          FWRITE(errhandle,substr(campo1,1,8)+substr(campo2,1,8)+&ret_line.) // ? substr(campo1,1,8)+substr(campo2,1,8)
          skip
          // Progress2()
      Enddo
      FCLOSE(errhandle) // set alter to
      nREG := recco() // Count to nREG
...

CPU 100% com o HARBOUR

Enviado: 30 Abr 2010 13:44
por Pablo César
mostrar em tela faz acesso IO (evite se puder para ganhar mais desempenho)
Aliás, você pode exibir, mas não de um a um, quem sabe de 100 em 100 ou 1000 em 1000. Dependerá a quantidade total de itens, você pode testar a gosto. Podendo até criar uma escala que dependendo o numero de itens você exiba (10, 100, 1000...) daí você dará uma folga pro processador e ainda deixará pro usuário a sensação de movimento.

Re: CPU 100% com o HARBOUR

Enviado: 03 Mai 2010 09:31
por levis_me
Srs., Bom Dia!

Fiz todas as alterações descritas, utilizando as funções de baixo nível e eliminando a barra de progresso, mas não mudou nda, o CPU continua em 100%.

CPU 100% com o HARBOUR

Enviado: 03 Mai 2010 10:57
por Pablo César
Mostre como ficou seu novo código.

Re: CPU 100% com o HARBOUR

Enviado: 03 Mai 2010 14:49
por levis_me
Ficou da seguinte forma:

Código: Selecionar todos

FUNCTION 2Col()
Peso:='8765432'
USE PRV
ZAP
	if Nmf = 0
		for j=0 to Qt
			a:=0
	      If Nm = 10000000
	      	Nm := 5000000
      	Endif      	
      	Num:=alltrim(strzero(nm,7))
	      for t=1 to 8
	         sm1:=val(subs(num,t,1)) * val(subs(Peso,t,1))
	         a+=sm1
	      next
	      nm++
	      dg:=mod(a,11)
		   dg2:=11-dg
		     	if j = qt1
		     		dbgotop()
	    		endif
		 		if j < qt1
            	PRV->(dbappend())
		     		PRV->campo1:=num+substr(Strzero(dg2,2),2,1)
	  			else
	    			PRV->campo2:=num+substr(Strzero(dg2,2),2,1)
	    			skip
	  			endif
	  			//Progress1() 
		next
		ret_line := "chr(13)+chr(10)" // Set alter on                             
      errhandle := FCREATE('2Col.txt') // Set alter to '2Col.txt'
      dbgotop()
      do While !Eof()
          FWRITE(errhandle,substr(campo1,1,8)+substr(campo2,1,8)+&ret_line.) // ? substr(campo1,1,8)+substr(campo2,1,8)
          skip
      	 //Progress2()
      Enddo
      FCLOSE(errhandle) // set alter to
      nREG := recco() // Count to nREG
		Digito.Label_1.Value:="Arquivo Gerado" + STR(nREG)

CPU 100% com o HARBOUR

Enviado: 03 Mai 2010 15:42
por Pablo César
Levis, a idéia seria também eliminar o acesso a gravação do dbf que você está usando-o de forma temporária. Pelo que entendí você precisa do primeiro registro e ultimo. Eu diria de você guardar em variáveis esse valor e descarregando linha a linha com FWRITE diretamente no arquivo texto a ser gerado. Também não entendí direito (pois desconheço variaveis qt e qt1) talvez seria substituido o primeiro registro ? Se for então, trabalhe diretamente com as variáveis (inicio e ultimo) e somente ao finalizar o processo, você irá descarregar no arquivo em forma de substituição. Seria isso ?

Qual é a função de qt1 ?
O quê é nm ? variavel que é passado por parâmetro é um campo que contém o quê ?
Crie variavel contador, para saber quantas linhas (ou registros) estão sendo gravados.

Se em vez de ser qt1 você quis dizer qt e qt é o parâmetro passado que define quantidade a ser processado, então tenho outra pergunta:

Para que serve você ir para gotop na segunda volta do looping (pois você começo com zero), se depois dessa linha você está colocando uma condição: if j < qt1 e neste caso quase sempre será menor a não ser que qt1 ou qt é a ultima volta limte.

As funções de baixo nível estariam no lugar errado se você eliminar o dbf, pois não precisa varrer um dbf para criar o arquivo texto, pode ir gerando.

Estou tentando exugar seu código, mas com erros fica dificil, não sei também se está completo...

Re: CPU 100% com o HARBOUR

Enviado: 04 Mai 2010 10:47
por Itamar M. Lins Jr.
Ola!
Use:

Código: Selecionar todos

milisec() 
//ou 
inkey(.1)
Para liberar o processador.
Se usar a Hwgui

Código: Selecionar todos

Do While
hwg_processmessage()
EndDo
Saudações,
Itamar M. Lins Jr.

Re: CPU 100% com o HARBOUR

Enviado: 04 Mai 2010 11:35
por Maligno
Exatamente! Um delay no meio do loop pára o processamento e dá folga suficiente para o escalonador do Windows trocar de tarefa, permitindo que outros processos concorrentes também usem a CPU. Pode parecer estranho, mas só esse delay já deve fazer o percentual de CPU diminuir.

Agora, se a tela do programa "congelar", talvez seja necessário também fazer a fila de mensagens do Windows receber alguma atenção. Daí será necessário algo do tipo ProcessMessage()¹ do Delphi. Ou essa tal função hwg_processmessage() da HWGUI que, pelo nome, não parece ser feita para liberar o processador, mas para dar foco à fila de mensagens.

Note que são duas coisas diferentes: o tempo extra para o escalonador do Windows poder atuar e o esvaziamento da fila de mensagens para evitar congelamentos, que podem ocorrer mesmo em sistemas que consomem pouca CPU.

Uma alternativa (bem) mais elaborada, para sistemas multicore, seria colocar a tarefa numa thread à parte e modificar a máscara de afinididade de processador para forçar a execução dessa thread em um core específico (ou em mais de um). Mas pelo trabalho que dá, a tarefa em si tem de ser realmente muito importante. Do contrário, não compensa.



¹ Essa função pára a aplicação e processa sua fila de mensagens até que ela esteja vazia, quando então o controle retorna à execução normal. Se a fila travar, mensagens do tipo "REPAINT", que desenham uma barra de progresso, por exemplo, ficam congelados.

Re: CPU 100% com o HARBOUR

Enviado: 04 Mai 2010 21:04
por levis_me

Código: Selecionar todos

milisec()
//ou
Do While
hwg_processmessage()
EndDo
Dão erro na compilação.

Já o

Código: Selecionar todos

inkey(.1)
funcionou, o CPU caiu para quase 0%, mas a geração do arquivo ficou extremamente lento, e também a tela do programa "congela", como ja vinha ocorrendo.

Re: CPU 100% com o HARBOUR

Enviado: 04 Mai 2010 21:10
por Maligno
O colega se distraiu e escreveu o nome errado. O correto é Millisec() que é, aliás, uma opção melhor, já que Inkey(0.1) significa 1/10 de segundo. Um tempo meio alto. Tente 1 ms. Se não der, vá aumentando.

Re: CPU 100% com o HARBOUR

Enviado: 04 Mai 2010 22:18
por sygecom
Qual versão do Harbour ?

Em vez de:
hwg_processmessage() // deve ser usado somente com Hwgui conforme o colega acima falou

use:
gtProcessMessages() ou NextKey()