Delphi 10.3.1發布了,對10.3.0存在的各種問題,做了大量的修正。但聽高勇說TNetHttpClient在多線程中存在問題,今天做了一下測試,確實如此,看來,還需要官方進一步修正!
具體測試方法,直接上代碼:
procedure TForm1.Button3Click(Sender: TObject); var i: Integer; begin for i := 1 to 3 do // 大於2,無法測試通過. begin TThread.CreateAnonymousThread( procedure() var aHttpClient: TNethttpClient; AResponseContent: Tstream; cnt: Integer; ContentLength: Integer; tid:Cardinal; begin cnt := 0; tid:=TThread.Current.ThreadID; aHttpClient := TNethttpClient.Create(Self);//建立NetHttpClient實例,並用他不斷的訪問同一網址。 try while true do begin Inc(cnt); // aHttpClient := TNethttpClient.Create(Self); AResponseContent := TMemoryStream.Create; try aHttpClient.Accept := 'text/javascript, text/html, application/xml, text/xml, /'; aHttpClient.AcceptLanguage := 'en-US,en;q=0.8,fr;q=0.6'; aHttpClient.UserAgent := 'Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36'; try aHttpClient.Get('https://www.cnblogs.com/kinglandsoft/p/10383103.html',AResponseContent);//開始訪問並返回結果到AResponseContent流中. except On E: Exception do begin TThread.Synchronize(nil, procedure() begin if Memo1.Lines.Count > 500 then Memo1.Lines.Clear; Memo1.Lines.Add(E.Message); end); end; end; ContentLength := AResponseContent.Size;//取得返回內容的長度,用來顯示 TThread.Synchronize(nil, procedure() var s: string; begin s := Format('cnt=%d,ContentLength:%d in thread id:%s', [cnt, ContentLength, tid.ToString]); Label1.Text := s; Memo1.Lines.Add(s); if Memo1.Lines.Count > 500 then Memo1.Lines.Clear; end); finally // aHttpClient.Free; AResponseContent.Free; end; end; // while true. finally aHttpClient.Free; end; end).Start; end; end;
實現思路,在線程中,建立一個NetHttpClient實例,用來訪問一個網址,同時建立幾個線程來運行NetHttpClient來訪問。結果,如果實例數=2,可以通過,大於2,則無法通過。另外換成HttpClient也是同樣的情況。此外,只是在android平台存在問題,win32平台正常。
向官方提交了這個問題,地址在https://quality.embarcadero.com/browse/RSP-23742,如果你也遇到,別忘記投一票,督促官方確認並修正。
跳過該問題的辦法,在官方沒有修正前,可以使用idHTTP來替代。
有解決方案了:
復制System.Net.HttpClient.pas單元到你的項目文件夾,修改THTTPClientExt的記錄結構為如下代碼:
THTTPClientExt = record case Integer of 0: ( FPreemptiveAuthentication: Boolean; FSecureFailureReasons: THTTPSecureFailureReasons; FAutomaticDecompression: THTTPCompressionMethods ); 1: ( _pad: array[0 .. 7] of Byte ); end;
測試通過。
另外,如果不復制System.Net.HttpClient.pas到你的項目目錄,則需要把System.Net.HttpClient.pas所在目錄加入項目的Search Path中。