Delphi > Obecné

Linux server multithread daemon

(1/1)

Andy:
Ahoj,
zkousim si napsat demona pro linux server, pouzil jsem jako zaklad https://github.com/paolo-rossi/linux-daemon
a jako jeden Thread to funguje vyborne, problem je ze tam mam dalsi Thread s websocket ktery taha data v realnem case.
kdyz pouziju v hlavnim okne jednoduche

--- Kód: Delphi ---    while running do    begin      Sleep(5000);    end; tak mi to blokuje Thread s websocketem
tak jsem pouzil

--- Kód: Delphi ---    while running do    begin      CheckSynchronize;    end; coz funguje, websocket taha data v realnem case, ale problem je ze i kdyz vypnu websocket (nevytvorim zadny thread) tak mi to zere 100%CPU

Setkal se s tim nekdo? Da se s tim neco delat aby ty vlakna nejak bezely soubezne a necekali jeden na druheho? nebo toho od konsolove aplikace chci moc?

Jan Fiala:
A proč nepoužiješ "opravdové" vlákno?

viz třeba:
https://forum.delphi.cz/index.php/topic,17418.0.html
Když vypneš websocket, tak vlákno ukonči, až ho budeš chtít zapnout, tak to celé zase spusť.

Tady máš víc informací i s popisem od Marca
https://blog.marcocantu.com/blog/2014_may_background_delphi_android_threads.html

pf1957:

--- Citace: Andy  13-05-2021, 19:04:19 ---a jako jeden Thread to funguje vyborne, problem je ze tam mam dalsi Thread s websocket ktery taha data v realnem case.

--- Konce citace ---
No protoze ten clanek se zabyva tim, jak vytvorit daemona tj. kazdou aplikaci, ktera ma bezet na pozadi bez interakce s uzivatelem a vlastni funkcionalitu aplikace neresi. Je to podobne, jako by ti nekdo popisoval, jak mas udelat z aplikace regulerni Windows Service, kterou nainstalujes, a Windows ji budou spoustet jeste pred prihlasenim jakehokoli uzivatele.

Vlastni thready musis naprogramovat sam, jak ti naznacil JF a muzes to cele udelat v bezne consolove aplikaci a az to budes mit hotove, tak pak to teprve formalne upravit, aby se to spoustelo samo na pozadi. Tak se to take prakticky dela, ze se aplikace da spoustet z command line/IDE, aby se to dalo ladit a nebo na option se nainstaluje jako sluzba/daemon. Ty anonymni thready se hodi na nejake jednorazove jednodujche akce, v komunikacich se spis pouzivaji explicitne vytvorene, pojmenovane thready se spravovanym zivotnim cyklem tj. potomkove TThread s vhodne prekrytymi metodami.


Andy:
Tak jsem to udelal jako prostou console app (na windows)
a vysledek je stejny, kdyz spi hlavni vlakno tak spi i vedlejsi
a funguje to jedine kdyz dam CheckSynchronize


--- Kód: Delphi ---program Project1; {$APPTYPE CONSOLE} {$R *.res} uses  System.SysUtils,  System.IOUtils,  System.Diagnostics,  System.TimeSpan,  System.Variants,  System.Classes,  System.Types,  System.JSON,  DateUtils,  System.Generics.Collections,  ScWebSocketClient; type  WSDownloader_BIN = class(TThread)    private      WebSocketClient: TScWebSocketClient;      GClientID : String;       GCanStart:Boolean;    protected      procedure WSReceiveData(Sender: TObject; const Data: TBytes;      MessageType: TScWebSocketMessageType; EndOfMessage: boolean);      procedure WriteToLogFile(Text: String);    published      constructor Create(ClientID:String);      destructor Destroy; override;      procedure ConnectToWSB;      procedure Execute(); override;  End; { WSDownloader_BIN } constructor WSDownloader_BIN.Create(ClientID:String);begin  inherited Create;  GCanStart:=true;  GClientID:=ClientID;  try    //CREATE WEBSOCKET    WebSocketClient := TScWebSocketClient.Create(nil);    WebSocketClient.HeartBeatOptions.Enabled := True;    WebSocketClient.WatchDogOptions.Enabled := True;    WebSocketClient.Options.RequestHeaders['Content-Language'] := 'en-US';    WebSocketClient.OnMessage := WSReceiveData;    WriteToLogFile('(CREATE)|SUCCESS|Thread '+GClientID+' created');  except ON E:Exception do    begin      GCanStart:=false;      WriteToLogFile('(CREATE)|ERROR|'+E.Message);    end;  end;  Self.FreeOnTerminate := True;end; destructor WSDownloader_BIN.Destroy;begin  try    WebSocketClient.Free;    WriteToLogFile('(DESTROY)|SUCCESS|Thread finished successfully');  except ON E:Exception do    WriteToLogFile('(DESTROY)|ERROR|'+E.Message);  end;  inherited;end; procedure WSDownloader_BIN.ConnectToWSB;begin  if GCanStart = false then begin    WriteToLogFile('(CONNECT_WS)|WARNING|Cant continue as previous step failed');    exit;  end;   try    WebSocketClient.Connect('wss://stream.binance.com:9443/stream?streams=bnbbtc@depth5@100ms');    WriteToLogFile('(CONNECT_WS)|SUCCESS|Connection to WebSocket created');  except ON E:Exception do    begin      GCanStart:=false;      WriteToLogFile('(CONNECT_WS)|ERROR|'+E.Message);    end;  end;end;  procedure WSDownloader_BIN.WriteToLogFile(Text: String);var  log: TextFile;  log_name: String;begin  try    log_name := 'client_'+GClientID+'.txt';    AssignFile(log, log_name);    if FileExists(log_name) then      Append(log)    else      Rewrite(log);    WriteLn(log, FormatDateTime('yyyy-mm-dd hh:nn:ss ', Now) + Text);    CloseFile(log);  except    // do nothing as its last instance of logging  end; end; procedure WSDownloader_BIN.WSReceiveData(Sender: TObject; const Data: TBytes;  MessageType: TScWebSocketMessageType; EndOfMessage: boolean);var  ReceivedText: string;begin  if MessageType = mtText then  begin    ReceivedText := TEncoding.Default.GetString(Data);    WriteToLogFile(ReceivedText);  end;end; procedure WSDownloader_BIN.Execute;begin  inherited;  ConnectToWSB;  //while not Terminated do begin  while (GCanStart) AND (not Terminated) do begin    sleep(1000);  end; end; var WebSocket:WSDownloader_BIN;   begin  try     WebSocket:=WSDownloader_BIN.Create('1');    while true do begin      {      kdyz odkomentuji sleep tak to nezatezuje procesor ale websoctek nebezi      potrebuji dostat stavu aby hlavni vlakno spalo a a bezelo jen to websocket      }      //sleep(2000);      {kdyz odkomentuji CheckSynchronize tak to bezi ale zatezuje to procesor}      //CheckSynchronize;      {kdyz neodkomentuji nic tak to zatezuje procesor}    end;  except    on E: Exception do      Writeln(E.ClassName, ': ', E.Message);  end;end. 

pf1957:

--- Citace: Andy  14-05-2021, 16:47:10 ---Tak jsem to udelal jako prostou console app (na windows)

--- Konce citace ---
To jsi vykrocil spravnym smerem


--- Citace ---a vysledek je stejny, kdyz spi hlavni vlakno tak spi i vedlejsi
a funguje to jedine kdyz dam CheckSynchronize

--- Konce citace ---
Nic o te komponentne TScWebSocketClient nevim, takze to ber s revervou, ale pokud pouziva event OnMessage, tak to IMHO znaci, ze ta komponenta ma nejaky vnitrni thread, ktery obsluhuje komunikaci a ten pravdepodobne vola pomoci Synchronize metodu, ktera je pro obsluhu OnMessage prirazena.

Ale metoda Synchronize funguje tak, ze adresu te metody strci do FIFO a vzbudi hlavni thread aplikace, aby tu adresu z fronty vyzvedl a zavolal a sama ceka, ze to hlavni thread udela... A pak je jasne, ze to potrebuje to CheckSynchronize, jinak nikdo ty zpravy z FIFO neodebira a nevola.

Ale hlavne: tohle neni to urceno pro komunikaci mezi podruznymi thready. Takze pokud to chces obsluhovat v jinem threadu nez hlavnim, tak bys mel zapomenout na OnMessage a misto toho volat metodu ReceiveMessage z metody Execute toho tveho threadu, kde chces prijata data zpracovavat.




Navigace

[0] Seznam témat

Přejít na plnou verzi