2012-02-12 27 views
6

Nunca he usado hilos, nunca pensé que mi código se beneficiaría. Sin embargo, creo que el roscado puede mejorar el rendimiento de la siguiente pseudo código:Enhebrado para mejorar el rendimiento

Loop through table of records containing security symbol field and a quote field 
    Load a web page (containing a security quote for a symbol) into a string variable 
    Parse the string for the quote 
    Save the quote in the table 
    Get next record 
end loop 

Cargando cada página web toma la mayor parte del tiempo. El análisis de la cita es bastante rápido. Supongo que podría tomar, digamos, la mitad de los registros de un hilo y trabajar la otra mitad en un segundo hilo.

+1

Utilice un marco de roscado, que se puede encontrar en las referencias a numerosas preguntas StackOverflow (hacer una búsqueda) – Misha

+5

Salida: http://www.thedelphigeek.com/2011/10/omnithreadlibrary-in-practice- 1web.html – gabr

+1

Me gustaría ir con omnithreadlibrary, es muy productivo, por cierto. mira omnixml también, ¡estas libs son extremadamente útiles! – ComputerSaysNo

Respuesta

4

En OmniThreadLibrary es muy simple resolver este problema con una tubería multietapa: la primera etapa se ejecuta en varias tareas y descarga páginas web y ejecuciones de segunda etapa en una instancia y almacena datos en la base de datos. He escrito un blog post que documenta esta solución hace algún tiempo.

La solución se puede resumir con el siguiente código (deberá completar algunos lugares en los métodos HttpGet e Inserter).

uses 
    OtlCommon, 
    OtlCollections, 
    OtlParallel; 

function HttpGet(url: string; var page: string): boolean; 
begin 
    // retrieve page contents from the url; return False if page is not accessible 
end; 

procedure Retriever(const input: TOmniValue; var output: TOmniValue); 
var 
    pageContents: string; 
begin 
    if HttpGet(input.AsString, pageContents) then 
    output := TPage.Create(input.AsString, pageContents); 
end; 

procedure Inserter(const input, output: IOmniBlockingCollection); 
var 
    page : TOmniValue; 
    pageObj: TPage; 
begin 
    // connect to database 
    for page in input do begin 
    pageObj := TPage(page.AsObject); 
    // insert pageObj into database 
    FreeAndNil(pageObj); 
    end; 
    // close database connection 
end; 

procedure ParallelWebRetriever; 
var 
    pipeline: IOmniPipeline; 
    s  : string; 
    urlList : TStringList; 
begin 
    // set up pipeline 
    pipeline := Parallel.Pipeline 
    .Stage(Retriever).NumTasks(Environment.Process.Affinity.Count * 2) 
    .Stage(Inserter) 
    .Run; 
    // insert URLs to be retrieved 
    for s in urlList do 
    pipeline.Input.Add(s); 
    pipeline.Input.CompleteAdding; 
    // wait for pipeline to complete 
    pipeline.WaitFor(INFINITE); 
end; 
4

Si el número de registros es relativamente pequeña, digamos 50 o menos, usted podría lanzar un hilo separado para cada registro y les deje todos corren en paralelo, por ejemplo:

begin thread 
    Load a web page for symbol into a string variable 
    Parse the string for the quote 
    Save the quote in the table 
end thread 

.

Loop through table of records 
    Launch a thread for current security symbol 
    Get next record 
end loop 

Si usted tiene un mayor número de registros a proceso, considerar el uso de un grupo de subprocesos para que pueda manejar registros en lotes más pequeños, por ejemplo:

Create X threads 
Put threads in a list 

Loop through table of records 
    Wait until a thread in pool is idle 
    Get idle thread from pool 
    Assign current security symbol to thread 
    Signal thread 
    Get next record 
end loop 

Wait for all threads to be idle 
Terminate threads 

.

begin thread 
    Loop until terminated 
    Mark idle 
    Wait for signal 
    If not Terminated 
     Load a web page for current symbol into a string variable 
     Parse the string for the quote 
     Save the quote in the table 
    end if 
    end loop 
end thread 

Existen muchas formas diferentes de implementarlo, razón por la cual lo dejé en un pseudocódigo. Mire las clases TThread, TList, y TEvent de la VCL, o la función Win32 API QueueUserWorkerItem(), o cualquier cantidad de bibliotecas de threading de terceros.

+1

Creo que una solución basada en tuberías es más adecuada aquí ya que las partes constituyentes de las tareas son de naturaleza bastante diferente. Al tirar hacia abajo de la descarga, se enlaza IO y el análisis del archivo está vinculado a la CPU. –

+0

@David: Tengo que investigar un poco sobre el "pipeline" porque nunca había oído hablar de él. Se apreciarán buenos enlaces de URL. –

+0

websearch hará el trabajo –

Cuestiones relacionadas