Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   MultiThread cada 5 Thread (https://www.clubdelphi.com/foros/showthread.php?t=90425)

Ramsay 06-06-2016 00:14:08

MultiThread cada 5 Thread
 
Hola , estoy usando multithread para comprobar paginas en un array largo , el tema es que funciona bien y todo , pero tendria que ser cada 10 o 5 Thread porque sino me consume mucho , me refiero a que cargue 5 thread y cuando terminen continue con otros 5 , el codigo de la unit de los threads.

Código Delphi [-]
unit ThreadsTest;

interface

uses Windows, Classes, IdHTTP;

type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  public
    Url: String;
    ReadTimeout: Integer;
    property ReturnValue;
  end;

implementation

procedure TMyThread.Execute;
var
  IdHTTP: TIdHTTP;
begin
  if Terminated then
    Exit;
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.ReadTimeout := ReadTimeout;
    IdHTTP.Get(Url);
    ReturnValue := 1;
  finally
    IdHTTP.Free;
  end;
end;

end.

Form

Código Delphi [-]
procedure TForm1.ThreadTerminado(Sender: TObject);
var
  LThread: TMyThread;
begin
  LThread := TMyThread(Sender);
  Inc(index);
  Memo1.Lines.Add(IntToStr(index) + '-' + LThread.Url + '-' +
    IntToStr(LThread.ReturnValue));
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: integer;
  index: integer;
const
  paginas: array [1 .. 13] of string = ('http://localhost1', 'http://localhost',
    'http://localhost', 'http://localhost', 'http://localhost',
    'http://localhost', 'http://localhost', 'http://localhost',
    'http://localhost', 'http://localhost', 'http://localhost',
    'http://localhost', 'http://localhost');
begin
  index := 0;
  for i := Low(paginas) to High(paginas) do
  begin
    LThread := TMyThread.Create(True);
    try
      LThread.Url := paginas[i];
      LThread.ReadTimeout := 1000;
      LThread.OnTerminate := ThreadTerminado;
      LThread.FreeOnTerminate := True;
    except
      LThread.Free;
      raise;
    end;
    LThread.Resume;
  end;
end;

El array real es mas largo.

¿ Como deberia hacer esto ?

mamcx 06-06-2016 04:54:07

La estrategia general es crear los 4 threads (lo que hace un "ThreadPool") al inicio y dejarlos *vivos*. Luego usas un un Queue que es el medio de comunicación, y lo usas para enviar y recibir los datos. Asi es mas simple.

https://stackoverflow.com/questions/...ueue-in-delphi

La libreria de Omnithread -que he usado y tiene eso y mucho mas-

Aqui lo hacen con envio de mensajes de windows, que tambien te podria servir):

http://delphi.about.com/od/kbthread/...ry-example.htm

Ramsay 07-06-2016 00:24:29

Hola , gracias por responder , esta todo perfecto y mas facil , solo me falta poder dar una respuesta al evento OnTerminate() por parte del CreateTask()

El codigo :

Código Delphi [-]
procedure TForm1.Button1Click(Sender: TObject);
const
  MSG_START = 1;
var
  iTask, numTasks, ReadTimeout: integer;
  url: string;
begin
  numTasks := 100;

  url := 'http://localhost/';
  ReadTimeout := 1000;

  for iTask := 1 to numTasks do
  begin
    Application.ProcessMessages;

    CreateTask(
      procedure(const task: IOmniTask)
      var
        ReadTimeout: integer;
        IdHTTP: TIdHTTP;
        url: string;
        ReturnValue:integer;
      begin
        task.Comm.Send(MSG_START);

        url := task.Param['Url'].AsString;
        ReadTimeout := task.Param['ReadTimeout'].AsInteger;
        ReturnValue := 0;

        IdHTTP := TIdHTTP.Create(nil);
        try
          IdHTTP.ReadTimeout := ReadTimeout;
          IdHTTP.Get(url);
          ReturnValue := 1;
        finally
          IdHTTP.Free;
        end;

        // some task workload
        // Sleep(sleepTime);
      end).OnMessage(
      procedure(const task: IOmniTaskControl; const msg: TOmniMessage)
      var
        taskNumber: integer;
      begin
        if msg.MsgID = MSG_START then
        begin
          taskNumber := task.Param['ReadTimeout'].AsInteger;

          LogPoolStatus(Format('task %d / %d start', [taskNumber,
            task.UniqueID]));
        end;
      end).OnTerminated(
      procedure(const task: IOmniTaskControl)
      begin
        // Aca muestro el ReturnValue
        LogPoolStatus(Format('task id %d terminated', [task.UniqueID]));
      end).SetParameter('url', url).SetParameter('ReadTimeout', ReadTimeout)
      .Unobserved.Schedule;
  end;

  // wait all finished
  while GlobalOmniThreadPool.CountExecuting +
    GlobalOmniThreadPool.CountQueued > 0 do
    Application.ProcessMessages;

  // all task completed
  LogPoolStatus('ALL DONE');
end;

Me refiero a poder usar la variable ReturnValue que tenia en el codigo viejo en el Create() , si el idhttp sale bien entonces retorna 1 , si sale mal 0 , y poder leer la variable ReturnValue en el evento OnTerminated.Ya probe manualmente pero parece que si uso la variable en el Create() no llega a leerse en el OnTerminated().
Solo me falta ese pequeño detalle , espero haberme explicado bien ,ya casi termino.

¿ Como deberia hacerlo ?

jars 08-06-2016 14:24:49

Hay algo como la libreria "Omnithread" para Delphi 7?
Gracias

mamcx 08-06-2016 16:05:39

Pues es lo que tienes con LogPoolStatus: Le estas enviando a ese metodo cada resultado. Hay tienes que, un Memo? Pues sea un memo o una lista vas acumulando los resultados en una estructura, al final, tienes algo como Memo.Lines <- ese es tu resultado!

Ramsay 08-06-2016 16:18:30

Si ,gracias por responder , tambien vi que se puede enviar un msg al onmessage() con los datos pero no al onterminate() , pero algo que no entiendo es cuando el proceso esta hecho en cada thread , parece que todo puede terminar en el createtask() , ¿ entonces para que uso onmessage() y onterminate() ? ¿ todo termina en el onmessage() ? , es que no entiendo estos eventos ...

mamcx 08-06-2016 17:00:47

Es mejor si lees la documentacion:

http://otl.17slon.com/tutorials.htm

Ramsay 08-06-2016 17:08:49

Si , ya los lei por eso pregunto la duda , uso createtask() con el codigo a usar y muestro el resultado en onmessage() , ¿ eso seria lo correcto ?


La franja horaria es GMT +2. Ahora son las 07:59:32.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi