Buenas a todos,
Me complace colocar aqu铆 el c贸digo que os va a permitir indexar multihilo bajo HARBOUR!
En la anterior versi贸n, se lanzaban 5 hilos, y se ESPERABA a que terminaran los 5.
La idea estaba bien, pero, 驴 que pasa cuando te encuentras que hay una tabla con un mill贸n de registros y 13 indices entre uno de los hilos ?
Pues que 4 hilos hab铆an terminado , y est谩bamos pendiente de esta tabla para continuar.
En esta revisi贸n, he implementado que cuando un hilo se termina, a continuaci贸n entra otro, y de esta manera, siempre est谩n 5 hilos corriendo,
independientemente de si la tabla es grande, peque帽a o tiene muchos indices.
Lo 煤nico que necesit谩is es solamente implementar la funci贸n LoadArray() que devuelve un array de arrays, o
crear un array como se indica, para las variables;
aFicheros := LoadArray()
aDbfs := aFicheros[1] //Array de Dbfs , { "dbf1,"dbf2", .... }
aNtxs := aFicheros[2] //MultiArray de Index { { "ntx_dbf1"} , { "ntx1_dbf2","ntx2_dbf2" } , ...}
aKeys := aFicheros[3] //MultiArray de Index { { "akey1_dbf1_ntx1"} , { "akey1_dbf2_ntx1","akey1_dbf2_ntx2" } , ...}
aFor := aFicheros[4] //MultiArray de aFor { { "afor1_dbf1_ntx1"} , { "for1_dbf2_ntx1","for1_dbf2_ntx2" } , ...} , Si no hay for, entonces valor a NIL, pero hay que ponerlo.
L贸gicamente, esto deber铆amos ejecutarlo contra alguna m谩quina que contenga al menos un micro con varios nucleos para ver diferencias sustanciales, de lo contrario,
hasta puede tener una personalizaci贸n he ir m谩s lento que uno por uno.
Si alguien tiene alguna idea o mejora sobre el c贸digo, no deje de compartirla!, como por ejemplo, otros RDDs como CDX, etc..
Espero les guste y cuenten experiencias.
Me complace colocar aqu铆 el c贸digo que os va a permitir indexar multihilo bajo HARBOUR!
En la anterior versi贸n, se lanzaban 5 hilos, y se ESPERABA a que terminaran los 5.
La idea estaba bien, pero, 驴 que pasa cuando te encuentras que hay una tabla con un mill贸n de registros y 13 indices entre uno de los hilos ?
Pues que 4 hilos hab铆an terminado , y est谩bamos pendiente de esta tabla para continuar.
En esta revisi贸n, he implementado que cuando un hilo se termina, a continuaci贸n entra otro, y de esta manera, siempre est谩n 5 hilos corriendo,
independientemente de si la tabla es grande, peque帽a o tiene muchos indices.
Lo 煤nico que necesit谩is es solamente implementar la funci贸n LoadArray() que devuelve un array de arrays, o
crear un array como se indica, para las variables;
aFicheros := LoadArray()
aDbfs := aFicheros[1] //Array de Dbfs , { "dbf1,"dbf2", .... }
aNtxs := aFicheros[2] //MultiArray de Index { { "ntx_dbf1"} , { "ntx1_dbf2","ntx2_dbf2" } , ...}
aKeys := aFicheros[3] //MultiArray de Index { { "akey1_dbf1_ntx1"} , { "akey1_dbf2_ntx1","akey1_dbf2_ntx2" } , ...}
aFor := aFicheros[4] //MultiArray de aFor { { "afor1_dbf1_ntx1"} , { "for1_dbf2_ntx1","for1_dbf2_ntx2" } , ...} , Si no hay for, entonces valor a NIL, pero hay que ponerlo.
/*
聽 2 REVISION, 5 Threads corriendo....always!!
聽 聽Example multiThreads index.
聽 聽One thread by table , and one thread by index.
聽 聽2010 Rafa Carmona
聽 聽Thread Main
聽 聽 聽 聽 |---------> 聽table for test.dbf
聽 聽 聽 聽 | 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽|----> Thread child index fname
聽 聽 聽 聽 | 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽|
聽 聽 聽 聽 | 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽|----->Thread child index fcode
聽 聽c:\> ..\..\bin\win\bcc\hbmk2 -mt indexpms -lhbcpage -Le:\harbour\trunk\harbour\lib\win\bcc
聽*/
#include "hbclass.ch"
#include "hbthread.ch"
#include "inkey.ch"
#include "common.ch"
REQUEST HB_CODEPAGE_ES850, HB_CODEPAGE_ES850C
REQUEST HB_LANG_ES
#define N_THREADS 5
STATIC nTecla
STATIC s_num_procesos
STATIC s_aLineas := { 1, 16, 32, 48, 64 }
static s_hMutex
proc Main( cTable_Dbf )
聽 聽 Local nSeconds
聽 聽 Local cDbf, lProcesa := .F.
聽 聽 Local aFicheros, x
聽 聽 Local aDbfs, aNtxs, aKeys , aDesc, aFor, aSel
聽 聽 Local aThreads := {}
聽 聽 Local nProceso := 0, nLinea, lSalir := .F., nIndex
聽 聽 Local nLen_Table
聽 聽 Local nPosTable
聽 聽 DEFAULT cTable_Dbf TO "TODOS"
聽 聽 聽//HB_SetCodePage( "ES850C" ) En xHarbour
聽 聽 set( _SET_CODEPAGE, "ES850C" ) 聽// Para Clipper Compatible
聽 聽 HB_LANGSELECT('ES')
聽 聽 Set( _SET_LANGUAGE, "ES" )
聽 聽 setmode( 25,80 )
聽 聽 cls
聽 聽 if empty( cTable_Dbf )
聽 聽 聽 聽ctable_dbf := ""
聽 聽 endif
聽 聽 @01,0 SAY padc( hb_ansitooem( " 聽Indexaci贸n m煤ltiple. (c)2010 Rafa Carmona" ), 80 )COLOR "N*/W*"
聽 聽 @23,0 SAY padc( "Pulse ESC para cancelar." , 80) COLOR "R+/N"
聽 聽 aFicheros := LoadArray()
聽 聽 aDbfs := aFicheros[1]
聽 聽 aNtxs := aFicheros[2]
聽 聽 aKeys := aFicheros[3]
聽 聽 aFor 聽:= aFicheros[4]
聽 聽 nLen_Table := len( aDbfs )
聽 聽 nPosTable 聽:= 1
聽 聽 nSeconds := Seconds()
聽 聽 s_num_procesos := 0
聽 聽 s_hMutex := hb_mutexCreate()
聽 聽while nPosTable <= nLen_Table
聽 聽 聽 聽 if ( nTecla := inkey() ) = K_ESC
聽 聽 聽 聽 聽 聽exit
聽 聽 聽 聽 endif
聽 聽 聽 聽 if N_THREADS = s_num_procesos // No se ha muerto ningun proceso
聽 聽 聽 聽 聽 loop
聽 聽 聽 聽 endif
聽 聽 聽 聽 cDbf := aDbfs[ nPosTable ]
聽 聽 聽 聽 do case
聽 聽 聽 聽 聽 聽case UPPER( cTable_Dbf 聽) == "TODOS"
聽 聽 聽 聽 聽 聽 聽 聽 lProcesa := .T.
聽 聽 聽 聽 聽 聽case UPPER( alltrim( cTable_Dbf ) ) == UPPER( alltrim( cDbf ) )
聽 聽 聽 聽 聽 聽 聽 聽 lProcesa := .T.
聽 聽 聽 聽 聽 聽otherwise
聽 聽 聽 聽 聽 聽 聽 聽 lProcesa := .F.
聽 聽 聽 聽 end case
聽 聽 聽 聽 if lProcesa .and. file( cDbf+".dbf" )
聽 聽 聽 聽 聽 聽hb_mutexLock( s_hMutex )
聽 聽 聽 聽 聽 聽s_num_procesos++
聽 聽 聽 聽 聽 聽hb_mutexUnLock( s_hMutex )
聽 聽 聽 聽 聽 聽hb_threadStart( @aCreateIndexe(), cDbf, aNtxs[ nPosTable ], aKeys[ nPosTable ], aFor[ nPosTable ] 聽)
聽 聽 聽 聽 聽 聽hb_idleSleep(0.05)
聽 聽 聽 聽 endif
聽 聽 聽 聽 nPosTable++
聽 聽 end while
聽 @23,1 SAY "Espere, terminado reindexaciones pendientes..." + space( 50 ) COLOR "R*/N"
聽 hb_threadWaitForAll() // Esperamos a los ultimos.
聽 @23,1 SAY "Proceso de indexacion terminado..." + Str( (Seconds() - nSeconds) /60 ) + space( 50 ) COLOR "W+/N"
return
function aCreateIndexe( cFile, aNtx, aExpr, aFor )
聽 聽 聽 聽Local nContador := 1
聽 聽 聽 聽Local cFileNtx, cExpr
聽 聽 聽 聽Local aThreads := {}
聽 聽 聽 聽Local cAlias, cFor
聽 聽 聽 聽Local 聽nP, x
聽 聽 聽 聽for x := 1 to 5
聽 聽 聽 聽 聽 nPosLinea := s_aLineas[ x ]
聽 聽 聽 聽 聽 if !empty( nPosLinea )
聽 聽 聽 聽 聽 聽 聽 s_aLineas[x] := 0 聽// Quita del array esa linea disponible para pintar
聽 聽 聽 聽 聽 聽 聽 exit
聽 聽 聽 聽 聽 endif
聽 聽 聽 聽next
聽 聽 聽 聽@ 2, nPosLinea CLEAR TO 15, nPosLinea + 14 // Limpiamos cuadrado
聽 聽 聽 聽hb_dispOutAt( 2, nPosLinea , cFile )
聽 聽 聽 聽use ( cFile )
聽 聽 聽 聽cAlias := alias()
聽 聽 聽 聽hb_dbDetach( cAlias ) 聽// Libero el alias
聽 聽 聽 聽for each cFileNtx in aNtx
聽 聽 聽 聽 聽 聽cExpr 聽:= aExpr[ cFileNtx:__enumindex ]
聽 聽 聽 聽 聽 聽cFor 聽 := aFor[ cFileNtx:__enumindex ]
聽 聽 聽 聽 聽 聽nPos 聽 := cFileNtx:__enumindex
聽 聽 聽 聽 聽 聽delete file ( cFileNtx +".ntx") 聽// Se borra el fichero, por ahorro de espacio en disco.
聽 聽 聽 聽 聽 聽aadd( aThreads, hb_threadStart( @crea(), cAlias,cExpr, cFileNtx, cFor, nPos, nPosLinea ) )
聽 聽 聽 聽 聽 聽if ( nTecla := inkey() ) = K_ESC 聽// No protegemos variable static
聽 聽 聽 聽 聽 聽 聽 exit
聽 聽 聽 聽 聽 聽endif
聽 聽 聽 聽next
聽 聽 聽 聽aEval( aThreads, { |x| hb_threadJoin( x ) } ) 聽// Espera que termine los hilos hijos
聽 聽 聽 聽hb_dbRequest( cAlias, , , .T.) 聽// Restaura el alias
聽 聽 聽 聽close
聽 聽 聽 聽// Vuelve a coloar la linea como disponible para pintar
聽 聽 聽 聽s_aLineas[x] := nPosLinea
聽 聽 聽 聽hb_mutexLock( s_hMutex )
聽 聽 聽 聽s_num_procesos--
聽 聽 聽 聽hb_mutexUnLock( s_hMutex )
RETURN .T.
proc crea( cAlias, cExpr, cFileNtx, cFor, nPos, nPosLinea )
聽 聽 聽 Local nContador := 1
聽 聽 聽 聽hb_dbRequest( cAlias, , , .T.) 聽// Restaura el alias
聽 聽 聽 聽if empty( cfor )
聽 聽 聽 聽 聽 聽INDEX ON &(cExpr) TO &(cFileNtx) ;
聽 聽 聽 聽 聽 聽 聽 聽 聽EVAL {|| hb_dispOutAt( nPos +3, nPosLinea, padr( cFileNtx,8 )+ "-"+alltrim( hb_valtostr( nContador) ), "GR+/N" ), nContador += INT( LASTREC() / 100 ) , .T. } ;
聽 聽 聽 聽 聽 聽 聽 聽 聽EVERY INT( LASTREC() / 100 )
// 聽 聽 聽 聽 聽 聽 聽 聽 EVAL {|| hb_dispOutAt( nPos +2, nPosLinea, padr( cFileNtx,8 )+ "-"+ padr( cExpr,20)+ " # " +alltrim( hb_valtostr( nContador) ), "GR+/N" ), nContador += INT( LASTREC() / 100 ) , .T. } ;
聽 聽 聽 聽else
聽 聽 聽 聽 聽 聽INDEX ON &(cExpr) TO &(cFileNtx) FOR &(cFor) ;
聽 聽 聽 聽 聽 聽 聽 聽 聽EVAL {|| hb_dispOutAt( nPos +3, nPosLinea, padr( cFileNtx,8 )+ "-"+alltrim( hb_valtostr( nContador) ), "GR+/N" ), nContador += INT( LASTREC() / 100 ) , .T. } ;
聽 聽 聽 聽 聽 聽 聽 聽 聽EVERY INT( LASTREC() / 100 )
聽 聽 聽 聽endif
聽 聽 聽 聽hb_dbDetach( cAlias ) 聽 聽 聽 聽 聽// Libera el alias
returnL贸gicamente, esto deber铆amos ejecutarlo contra alguna m谩quina que contenga al menos un micro con varios nucleos para ver diferencias sustanciales, de lo contrario,
hasta puede tener una personalizaci贸n he ir m谩s lento que uno por uno.
Si alguien tiene alguna idea o mejora sobre el c贸digo, no deje de compartirla!, como por ejemplo, otros RDDs como CDX, etc..
Espero les guste y cuenten experiencias.
Saludos
Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)
Rafa Carmona ( rafa.thefullARROBAgmail.com___quitalineas__)