Autor Téma: Linux server multithread daemon  (Přečteno 263 krát)

Offline Andy

  • Mladík
  • **
  • Příspěvků: 68
  • Karma: 0
Linux server multithread daemon
« kdy: 13-05-2021, 19:04:19 »
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 [Vybrat]
  1.     while running do
  2.     begin
  3.       Sleep(5000);
  4.     end;
  5.  
tak mi to blokuje Thread s websocketem
tak jsem pouzil
Kód: Delphi [Vybrat]
  1.     while running do
  2.     begin
  3.       CheckSynchronize;
  4.     end;
  5.  
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?

Offline Jan Fiala

  • Plnoletý
  • ***
  • Příspěvků: 183
  • Karma: 2
    • Verze Delphi: 10.4.1
    • PSPad editor
Re:Linux server multithread daemon
« Odpověď #1 kdy: 14-05-2021, 07:23:13 »
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

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3178
  • Karma: 137
    • Verze Delphi: D2007, XE3, DX10
Re:Linux server multithread daemon
« Odpověď #2 kdy: 14-05-2021, 11:10:22 »
a jako jeden Thread to funguje vyborne, problem je ze tam mam dalsi Thread s websocket ktery taha data v realnem case.
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.


« Poslední změna: 14-05-2021, 11:11:58 od pf1957 »

Offline Andy

  • Mladík
  • **
  • Příspěvků: 68
  • Karma: 0
Re:Linux server multithread daemon
« Odpověď #3 kdy: 14-05-2021, 16:47:10 »
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 [Vybrat]
  1. program Project1;
  2.  
  3. {$APPTYPE CONSOLE}
  4.  
  5. {$R *.res}
  6.  
  7. uses
  8.   System.SysUtils,
  9.   System.IOUtils,
  10.   System.Diagnostics,
  11.   System.TimeSpan,
  12.   System.Variants,
  13.   System.Classes,
  14.   System.Types,
  15.   System.JSON,
  16.   DateUtils,
  17.   System.Generics.Collections,
  18.   ScWebSocketClient;
  19.  
  20. type
  21.   WSDownloader_BIN = class(TThread)
  22.     private
  23.       WebSocketClient: TScWebSocketClient;
  24.       GClientID : String;
  25.  
  26.       GCanStart:Boolean;
  27.     protected
  28.       procedure WSReceiveData(Sender: TObject; const Data: TBytes;
  29.       MessageType: TScWebSocketMessageType; EndOfMessage: boolean);
  30.       procedure WriteToLogFile(Text: String);
  31.     published
  32.       constructor Create(ClientID:String);
  33.       destructor Destroy; override;
  34.       procedure ConnectToWSB;
  35.       procedure Execute(); override;
  36.   End;
  37.  
  38. { WSDownloader_BIN }
  39.  
  40. constructor WSDownloader_BIN.Create(ClientID:String);
  41. begin
  42.   inherited Create;
  43.   GCanStart:=true;
  44.   GClientID:=ClientID;
  45.   try
  46.     //CREATE WEBSOCKET
  47.     WebSocketClient := TScWebSocketClient.Create(nil);
  48.     WebSocketClient.HeartBeatOptions.Enabled := True;
  49.     WebSocketClient.WatchDogOptions.Enabled := True;
  50.     WebSocketClient.Options.RequestHeaders['Content-Language'] := 'en-US';
  51.     WebSocketClient.OnMessage := WSReceiveData;
  52.     WriteToLogFile('(CREATE)|SUCCESS|Thread '+GClientID+' created');
  53.   except ON E:Exception do
  54.     begin
  55.       GCanStart:=false;
  56.       WriteToLogFile('(CREATE)|ERROR|'+E.Message);
  57.     end;
  58.   end;
  59.   Self.FreeOnTerminate := True;
  60. end;
  61.  
  62. destructor WSDownloader_BIN.Destroy;
  63. begin
  64.   try
  65.     WebSocketClient.Free;
  66.     WriteToLogFile('(DESTROY)|SUCCESS|Thread finished successfully');
  67.   except ON E:Exception do
  68.     WriteToLogFile('(DESTROY)|ERROR|'+E.Message);
  69.   end;
  70.   inherited;
  71. end;
  72.  
  73. procedure WSDownloader_BIN.ConnectToWSB;
  74. begin
  75.   if GCanStart = false then begin
  76.     WriteToLogFile('(CONNECT_WS)|WARNING|Cant continue as previous step failed');
  77.     exit;
  78.   end;
  79.  
  80.   try
  81.     WebSocketClient.Connect('wss://stream.binance.com:9443/stream?streams=bnbbtc@depth5@100ms');
  82.     WriteToLogFile('(CONNECT_WS)|SUCCESS|Connection to WebSocket created');
  83.   except ON E:Exception do
  84.     begin
  85.       GCanStart:=false;
  86.       WriteToLogFile('(CONNECT_WS)|ERROR|'+E.Message);
  87.     end;
  88.   end;
  89. end;
  90.  
  91.  
  92. procedure WSDownloader_BIN.WriteToLogFile(Text: String);
  93. var
  94.   log: TextFile;
  95.   log_name: String;
  96. begin
  97.   try
  98.     log_name := 'client_'+GClientID+'.txt';
  99.     AssignFile(log, log_name);
  100.     if FileExists(log_name) then
  101.       Append(log)
  102.     else
  103.       Rewrite(log);
  104.     WriteLn(log, FormatDateTime('yyyy-mm-dd hh:nn:ss ', Now) + Text);
  105.     CloseFile(log);
  106.   except
  107.     // do nothing as its last instance of logging
  108.   end;
  109.  
  110. end;
  111.  
  112. procedure WSDownloader_BIN.WSReceiveData(Sender: TObject; const Data: TBytes;
  113.   MessageType: TScWebSocketMessageType; EndOfMessage: boolean);
  114. var
  115.   ReceivedText: string;
  116. begin
  117.   if MessageType = mtText then
  118.   begin
  119.     ReceivedText := TEncoding.Default.GetString(Data);
  120.     WriteToLogFile(ReceivedText);
  121.   end;
  122. end;
  123.  
  124. procedure WSDownloader_BIN.Execute;
  125. begin
  126.   inherited;
  127.   ConnectToWSB;
  128.   //while not Terminated do begin
  129.   while (GCanStart) AND (not Terminated) do begin
  130.     sleep(1000);
  131.   end;
  132.  
  133. end;
  134.  
  135. var
  136.  
  137. WebSocket:WSDownloader_BIN;
  138.  
  139.  
  140.  
  141. begin
  142.   try
  143.  
  144.     WebSocket:=WSDownloader_BIN.Create('1');
  145.     while true do begin
  146.       {
  147.       kdyz odkomentuji sleep tak to nezatezuje procesor ale websoctek nebezi
  148.       potrebuji dostat stavu aby hlavni vlakno spalo a a bezelo jen to websocket
  149.       }
  150.       //sleep(2000);
  151.       {kdyz odkomentuji CheckSynchronize tak to bezi ale zatezuje to procesor}
  152.       //CheckSynchronize;
  153.       {kdyz neodkomentuji nic tak to zatezuje procesor}
  154.     end;
  155.   except
  156.     on E: Exception do
  157.       Writeln(E.ClassName, ': ', E.Message);
  158.   end;
  159. end.
  160.  

Offline pf1957

  • Padawan
  • ******
  • Příspěvků: 3178
  • Karma: 137
    • Verze Delphi: D2007, XE3, DX10
Re:Linux server multithread daemon
« Odpověď #4 kdy: 15-05-2021, 07:56:32 »
Excellent
Rated 1 time
Tak jsem to udelal jako prostou console app (na windows)
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
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.