Tôi đến bữa tiệc muộn, nhưng đây là hành trình học hỏi của tôi về chủ đề khó khăn này.
1. Chúng ta có thể tìm thấy người ủng hộ chính thức về việc tái sử dụng HTTPClient ở đâu?
Ý tôi là, nếu việc sử dụng lại httpClient được dự định
và làm như vậy là rất quan trọng , thì người ủng hộ đó được ghi lại tốt hơn trong tài liệu API của riêng mình, thay vì bị ẩn trong nhiều "Chủ đề nâng cao", "Mẫu hiệu suất (chống)" hoặc các bài đăng trên blog khác ngoài đó . Nếu không thì làm thế nào một người học mới phải biết nó trước khi quá muộn?
Kể từ bây giờ (tháng 5 năm 2018), kết quả tìm kiếm đầu tiên khi googling "c # httpclient" trỏ đến trang tham chiếu API này trên MSDN , hoàn toàn không đề cập đến ý định đó. Vâng, bài học 1 ở đây cho người mới là, luôn nhấp vào liên kết "Phiên bản khác" ngay sau tiêu đề trang trợ giúp MSDN, bạn có thể sẽ tìm thấy các liên kết đến "phiên bản hiện tại" ở đó. Trong trường hợp httpClient này, nó sẽ đưa bạn đến tài liệu mới nhất
ở đây có chứa mô tả ý định đó .
Tôi nghi ngờ nhiều nhà phát triển mới tham gia chủ đề này cũng không tìm thấy trang tài liệu chính xác, đó là lý do tại sao kiến thức này không được phổ biến rộng rãi và mọi người đã ngạc nhiên khi họ phát hiện ra
sau đó , có thể là một cách khó khăn .
2. Quan niệm (mis?) Của using
IDisposable
Cái này là hơi lạc đề nhưng vẫn có giá trị chỉ ra rằng, nó không phải là một trùng hợp ngẫu nhiên khi thấy mọi người trong những bài đăng trên blog nói trên đổ lỗi như thế nào HttpClient
's IDisposable
giao diện làm cho họ có xu hướng sử dụng các using (var client = new HttpClient()) {...}
mô hình và sau đó dẫn đến các vấn đề.
Tôi tin rằng điều đó dẫn đến một quan niệm bất thành văn (mis?):
"Một đối tượng IDis Dùng được dự kiến sẽ tồn tại trong thời gian ngắn" .
TUY NHIÊN, trong khi nó chắc chắn trông giống như một thứ tồn tại ngắn khi chúng ta viết mã theo phong cách này:
using (var foo = new SomeDisposableObject())
{
...
}
các tài liệu chính thức về IDisposable
không bao giờ đề cập đến IDisposable
đối tượng phải là ngắn ngủi. Theo định nghĩa, IDis Dùng chỉ là một cơ chế để cho phép bạn giải phóng các tài nguyên không được quản lý. Chỉ có bấy nhiêu thôi. Theo nghĩa đó, bạn được MỞ RỘNG để cuối cùng kích hoạt xử lý, nhưng nó không yêu cầu bạn phải làm như vậy trong một thời gian ngắn.
Do đó, công việc của bạn là chọn đúng thời điểm để kích hoạt xử lý, dựa trên yêu cầu vòng đời của đối tượng thực của bạn. Không có gì ngăn bạn sử dụng IDis Dùng một cách lâu dài:
using System;
namespace HelloWorld
{
class Hello
{
static void Main()
{
Console.WriteLine("Hello World!");
using (var client = new HttpClient())
{
for (...) { ... } // A really long loop
// Or you may even somehow start a daemon here
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
}
Với cách hiểu mới này, bây giờ chúng tôi xem lại bài đăng trên blog đó , chúng tôi có thể nhận thấy rõ rằng "sửa chữa" khởi tạo HttpClient
một lần nhưng không bao giờ loại bỏ nó, đó là lý do tại sao chúng tôi có thể thấy từ đầu ra netstat của nó, kết nối vẫn ở trạng thái THÀNH LẬP có nghĩa là nó có KHÔNG được đóng đúng cách. Nếu nó bị đóng, thay vào đó, trạng thái của nó sẽ ở TIME_WAIT. Trong thực tế, không phải là vấn đề lớn khi chỉ rò rỉ một kết nối mở sau khi toàn bộ chương trình của bạn kết thúc và người đăng blog vẫn thấy hiệu suất tăng sau khi sửa lỗi; tuy nhiên, về mặt khái niệm không chính xác để đổ lỗi cho IDis Dùng và chọn KHÔNG loại bỏ nó.
3. Chúng ta có phải đặt httpClient vào một thuộc tính tĩnh hay thậm chí đặt nó dưới dạng đơn lẻ không?
Dựa trên sự hiểu biết của phần trước, tôi nghĩ rằng câu trả lời ở đây trở nên rõ ràng: "không nhất thiết". Nó thực sự phụ thuộc vào cách bạn tổ chức mã của mình, miễn là bạn sử dụng lại một HTTPClient VÀ (lý tưởng) để loại bỏ nó.
Vui vẻ, ngay cả ví dụ trong phần
Ghi chú của tài liệu chính thức hiện tại
cũng hoàn toàn đúng. Nó định nghĩa một lớp "GoodContoder", chứa thuộc tính httpClient tĩnh sẽ không bị loại bỏ; không tuân theo những gì một ví dụ khác trong phần Ví dụ
nhấn mạnh: "cần gọi xử lý ... vì vậy ứng dụng không bị rò rỉ tài nguyên".
Và cuối cùng, singleton không phải không có những thách thức riêng.
"Có bao nhiêu người nghĩ biến toàn cầu là một ý tưởng tốt? Không ai cả.
Có bao nhiêu người nghĩ singleton là một ý tưởng tốt? Một vài
Đưa cái gì? Singletons chỉ là một loạt các biến toàn cầu. "
- Trích dẫn từ bài nói chuyện đầy cảm hứng này, "Nhà nước toàn cầu và người độc thân"
PS: Kết nối Sql
Điều này không liên quan đến Q & A hiện tại, nhưng nó có lẽ là một điều cần biết. Mô hình sử dụng SqlConnection là khác nhau. Bạn KHÔNG cần phải sử dụng lại SqlConnection , bởi vì nó sẽ xử lý nhóm kết nối của nó tốt hơn theo cách đó.
Sự khác biệt được gây ra bởi phương pháp thực hiện của họ. Mỗi phiên bản httpClient sử dụng nhóm kết nối riêng của nó (trích dẫn từ
đây ); nhưng bản thân SqlConnection được quản lý bởi một nhóm kết nối trung tâm, theo điều này .
Và bạn vẫn cần phải loại bỏ SqlConnection, giống như bạn phải làm với HttpClient.