Каков оптимальный способ выполнить много параллельных веб-запросов, избегая утечек памяти и висячих сокетов? (С #) - PullRequest
0 голосов
/ 10 мая 2019

Мне нужно выполнять много веб-запросов параллельно (примерно 1000 в секунду).У некоторых из этих веб-запросов истекает время (сервер не отвечает), и я должен быть в состоянии справиться с этим.Многие запросы нужно будет направлять через прокси (и есть много разных прокси, которые нужно будет использовать).

Из-за необходимости использования прокси один HttpClient не может быть повторно использован (что является обычной практикой для выполнения нескольких запросов).Таким образом, наивный способ сделать это состоит в том, чтобы запустить несколько потоков, и в каждом из них создать новый HttpClient со своим собственным обработчиком и выполнить запрос.Но это все еще оставляет проблему оставления многих открытых розеток.Так что на самом деле это не вариант.

На данный момент я делаю следующее:

class GetRequest
    {
        private int timeout;
        private WebRequest req;
        private string url;
        private ManualResetEvent allDone;
        private string response;
        private IWebProxy proxy;

        public GetRequest(string url, int timeout = 3000, IWebProxy proxy = null)
        {
            this.url = url;
            this.timeout = timeout;
            this.response = "";
            this.proxy = proxy;
        }

        public string Get()
        {
            allDone = new ManualResetEvent(false);
            req = WebRequest.Create(url);
            req.Proxy = proxy;
            req.Headers[HttpRequestHeader.UserAgent] = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36";
            req.Timeout = this.timeout;

            req.BeginGetResponse(GetResponseCallback, req);
            allDone.WaitOne(timeout);
            Cleanup();
            return this.response;
        }
        private HttpWebResponse webresponse;
        private Stream streamResponse;
        private StreamReader streamRead;

        private void GetResponseCallback(IAsyncResult asynchronousResult)
        {

            // End the operation
            webresponse = (HttpWebResponse)req.EndGetResponse(asynchronousResult);
            streamResponse = webresponse.GetResponseStream();
            streamRead = new StreamReader(streamResponse);
            string responseString = streamRead.ReadToEnd();
            this.response = responseString;
            // Close the stream object
            streamResponse.Close();
            streamRead.Close();

            // Release the HttpWebResponse
            webresponse.Close();
            allDone.Set();
        }

        ~GetRequest()
        {
            Cleanup();
        }

        public void Cleanup()
        {
            try
            {
                streamResponse?.Close();
            } catch { }
            try
            {
                streamRead?.Close();
            }
            catch { }
            try
            {
                webresponse?.Close();
            }
            catch { }
        }
    }

Затем я могу запустить несколько потоков и создать новые GetRequest объекты, отправитьих, а затем позвоните Cleanup().

Достаточно ли этого, чтобы избежать утечек памяти и висячих сокетов?Есть ли лучший способ сделать это?

(извините за качество этого кода, в данный момент он находится на ранней стадии разработки)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...