powered by simpleCommunicator - 2.0.36     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / параллельные запросы HttpWebRequest
25 сообщений из 67, страница 1 из 3
параллельные запросы HttpWebRequest
    #40025094
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
в цикле в пуле потоков
Код: vbnet
1.
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf NwBra), id)

запускаю каждое обращение к сайту в отдельном потоке
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Private Sub NwBra(ByVal id As Object)
Dim fr As HttpWebRequest = DirectCast(HttpWebRequest.Create("https://www.site"), System.Net.HttpWebRequest)
        fr.ContentType = "application/x-www-form-urlencoded"
        fr.Method = "GET"
        Dim responseString As String = ""
        fr.GetResponse()
        Dim str As New System.IO.StreamReader(fr.GetResponse().GetResponseStream())
        responseString = str.ReadToEnd()
        str.Close()
End Sub

но всё равно запросы выполняются последовательно( подскажите, как заставить их обращаться параллельно, для 100 запросов время доходит до 20 секунд, что критично
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025101
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Почему ты просто не используешь GetResponseAsync?
К чему вся эта свистопляска с многопоточностью?
На шарпе можно примерно так (на VB уже сам переводи, если что):
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
const int ParallelCount = 100;
const string Url = "http://foo.bar.io";

var results = await Task.WhenAll(
    Enumerable.Repeat(0, ParallelCount).Select(async _ => {
        var webRequest = HttpWebRequest.Create(Url);
        using var response = await webRequest.GetResponseAsync();
        using var stream = response.GetResponseStream();
        using StreamReader reader = new(stream);
        return await reader.ReadToEndAsync();
    }));

foreach (var r in results)
{
    Console.WriteLine(r);
}
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025104
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

если я буду получать асинхронные ответы, то запросы ведь я всё равно буду отправлять последовательно, а это долго. поэтому вынес запросы-ответы в отдельные потоки, но не помогает что-то
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025106
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok
запросы ведь я всё равно буду отправлять последовательно
зачем ты будешь отправлять запросы последовательно, если выше привели код как отправлять их параллельно?
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025112
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Shocker.Pro,

я тупой и не могу прочесть( какие-то юсинги, енумераблы. сейчас сделал последовательную отправку запросов, повесил асинхронную обработку ответов, выполняется так же последовательно почему-то
Код: vbnet
1.
Dim result As IAsyncResult = CType(request.BeginGetResponse(AddressOf otpravkaonline3, request), IAsyncResult)
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025113
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

есть такой код на vb.net?) пожалуйста
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025115
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok,

На бейсике у меня вышло как-то так (я на нем ни разу в жизни не писал, т.ч. не знаю насколько это кошерно ):
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
Async Function Main(args As String()) As Task
    Dim count = 100
    Dim url = "foo.bar.baz"

    Dim results = Await Task.WhenAll(
        Enumerable.Repeat(0, 100).Select(
            Async Function(i As Int32)
                Dim webRequest = HttpWebRequest.Create(url)
                Using response = Await webRequest.GetResponseAsync()
                    Using stream = response.GetResponseStream()
                        Using reader = New StreamReader(stream)
                            Return Await reader.ReadToEndAsync()
                        End Using
                    End Using
                End Using
            End Function))

    For Each r In results
        Console.WriteLine(r)
    Next
End Function


А что, даже прикольно. Может мне на VB.NET мигрировать

По-хорошему надо конечно еще try-catch расставить, чтобы один упавший запрос не факапил все 99 остальных, но это уже ньюансы.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025116
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok
fkthat,

есть такой код на vb.net?) пожалуйста
https://converter.telerik.com
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025117
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник

Сейчас попробовал. Он, похоже, даже C# 8 не понимает.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025118
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну значит ТС пусть на шарп переходит.
Я абсолютно не понимаю, как кто-то может писать на VB.NET при практически полном отсутствии статей, учебников и документации.
Даже Microsoft перестал включать в современную документацию примеры на VB.NET.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025119
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro
Даже Microsoft перестал включать в современную документацию примеры на VB.NET.

https://devblogs.microsoft.com/vbteam/visual-basic-support-planned-for-net-5-0/ Going forward, we do not plan to evolve Visual Basic as a language . This supports language stability and maintains compatibility between the .NET Core and .NET Framework versions of Visual Basic. Future features of .NET Core that require language changes may not be supported in Visual Basic .

Так что я с миграцией на него все же поторопился :))
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025154
vb_sub
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сначала проверь, стоит ли вообще все в многопоток делать- может последовательно и быстрее получится конкретно в твоем случае.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025156
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
vb_sub
Сначала проверь, стоит ли вообще все в многопоток делать- может последовательно и быстрее получится конкретно в твоем случае.

Да на кой проверять. Многопоточность для I/O не нужна вообще никогда. Для него существуют неблокирующие async-вызовы.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025227
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

я честно пытался использовать код, и так и эдак его впихивал, но никак( синтаксис сложный для понимания или я тупой. в итоге вернулся к пулу потоков. так же в цикле отправляю в пул функцию без всяких асинхронностей (обращение и функция в самом посте). вывел в консоль номера потоков и обнаружил, что на 70 соединений у меня 3-4 потока. т.е. несмотря на умные статьи, где расхваливают автоматический подбор необходимого количества потоков, это чушь. задаю количество потоков и получаю прирост в несколько раз
Код: vbnet
1.
ThreadPool.SetMinThreads(20, 20)

далее увеличиваю количество одновременных соединений http и получаю прирост по скорости еще в несколько раз
Код: vbnet
1.
ServicePointManager.DefaultConnectionLimit = 50

. но всё равно код выполняется больше секунды для 70 соединений, это долго. что-то явно можно улучшить, буду благодарен, если подскажете, что. и цифры 20 и 50 я брал методом тыка. если увеличивать, начинают сыпаться ошибки соединения, какие цифры должны быть и от чего зависит, я хз(
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025232
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok
вернулся к пулу потоков.

qlewerok
Код: vbnet
1.
ThreadPool.SetMinThreads(20, 20)


Ну что поделать, тут или разбираться, как это надо делать (т.е. без ThreadPool и прочего легаси), либо потом отгребать последствия:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.threadpool.setminthreads?view=net-5.0#remarks Caution

By default, the minimum number of threads is set to the number of processors on a system. You can use the SetMinThreads method to increase the minimum number of threads. However, unnecessarily increasing these values can cause performance problems . If too many tasks start at the same time, all of them might appear to be slow. In most cases, the thread pool will perform better with its own algorithm for allocating threads. Reducing the minimum to less than the number of processors can also hurt performance .
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025258
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

ваш код выполняется 6 секунд. если увеличить количество макс соединений до 9, выполняется за 1.5 секунд, как и мой. если 10 соединений, то начинает сыпаться подключение, от чего зависит, опять же, не знаю
Код: vbnet
1.
ServicePointManager.DefaultConnectionLimit = 9

хочу использовать ваш код, но в нём выносит мозг строка
Код: vbnet
1.
Enumerable.Repeat(0, 100).Select(

все три слова впервые встречаю в языке. подскажете, как будет выглядеть код без неё? можно с разложением на несколько функций, а то там одна в другой как-то... и url у меня разные, передаются как раз в args As String()
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025270
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok
fkthat,

ваш код выполняется 6 секунд. если увеличить количество макс соединений до 9, выполняется за 1.5 секунд, как и мой. если 10 соединений, то начинает сыпаться подключение, от чего зависит, опять же, не знаю
Код: vbnet
1.
ServicePointManager.DefaultConnectionLimit = 9


хочу использовать ваш код, но в нём выносит мозг строка
Код: vbnet
1.
Enumerable.Repeat(0, 100).Select(


все три слова впервые встречаю в языке. подскажете, как будет выглядеть код без неё? можно с разложением на несколько функций, а то там одна в другой как-то... и url у меня разные, передаются как раз в args As String()


Enumerable.Repeat(0, 100) это библиотечный класс/метод который генерирует последовательность из 100 нулей. Select(...) берет поочередно каждый элемент этой последовательности (в данном случае это просто 0, но нам он не нужен, важно что их будет 100) и вызывает для этого элемента переданную в этот метод функцию, а затем возвращает последовательность получившихся значений. Поскольку мы передаем туда асинхронный метод, то то на выходе мы получим последовательность объектов Task. В свою очередь Task.WhenAll получает параметром последовательность этих тасков и возвращает в свою очередб один, типа как "таск тасков", т.е. таск, который будет завершен, когда завершатся все переданные ему таски. А самый верхний await (который await Task.WhenAll(...)) он уже "ждет" когда завершится этот "таск тасков" и результат его выполнения (массив строк) отдает дальше. Это можно переписать и без LINQ, просто на циклах, но, в данном случае, это будет длиннее.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025276
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok,

Вот, может так понять будет проще:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
Module Program

    Async Function Main(args As String()) As Task
        Dim count = 100
        Dim url = "foo.bar.baz"
        Dim tasks As New List(Of Task(Of String))

        For i = 0 To count - 1
            tasks.Add(DoRequest(url))
        Next

        Dim whenAll = Task.WhenAll(tasks)
        Dim results = Await whenAll

        ' В results у нас массив результатов всех запросов
        For Each r In results
            Console.WriteLine(r)
        Next
    End Function

    Async Function DoRequest(url As String) As Task(Of String)
        Dim webRequest = HttpWebRequest.Create(url)
        Using response = Await webRequest.GetResponseAsync()
            Using stream = response.GetResponseStream()
                Using reader = New StreamReader(stream)
                    ' Здесь можно сделать что-то с результатом отдельного запроса
                    Return Await reader.ReadToEndAsync()
                End Using
            End Using
        End Using
    End Function

End Module


...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025505
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

это код понятен, всё работает, большое спасибо) только он ведь однопоточный, что подтверждает
Код: vbnet
1.
Console.WriteLine(Thread.CurrentThread.ManagedThreadId)

код доходит до получения ответа первого соединения и, если ответ не готов, идёт дальше создавать второе соединение. когда ответ первого соединение готов, программа останавливает выполнение действий, возвращается к первому соединению, выполняет получение ответа и обработку, идёт дальше. и если ответы двух соединений получены одновременно, программа примет их последовательно. отсюда 40 одинаковых запросов выполняются в 4 раза дольше 1 соединения. да, не в 40 за счёт асинхронных ожиданий, но всё-таки не параллельно, а каждая миллисекунда критична
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025519
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat, добавь ему ConfigureAwait ))
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025521
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
qlewerok
fkthat,

это код понятен, всё работает, большое спасибо) только он ведь однопоточный, что подтверждает
Код: vbnet
1.
Console.WriteLine(Thread.CurrentThread.ManagedThreadId)


код доходит до получения ответа первого соединения и, если ответ не готов, идёт дальше создавать второе соединение. когда ответ первого соединение готов, программа останавливает выполнение действий, возвращается к первому соединению, выполняет получение ответа и обработку, идёт дальше. и если ответы двух соединений получены одновременно, программа примет их последовательно. отсюда 40 одинаковых запросов выполняются в 4 раза дольше 1 соединения. да, не в 40 за счёт асинхронных ожиданий, но всё-таки не параллельно, а каждая миллисекунда критична

Если ты хочешь распараллелить еще и обработку, то тебе надо саму обработку запускать в пуле потоков с помощью Task.Run(...). Но учти, что если у тебя много времени занимает именно обработка запроса, то в любом случае выгода будет только если у тебя много ядер CPU.

Вот, например, как-то так:


Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
Module Program

    Sub Main(args As String())
        Dim count = 100
        Dim url = "foo.bar.baz"
        Dim tasks As New List(Of Task)

        For i = 0 To count - 1
            tasks.Add(DoRequest(url))
        Next

        Dim whenAll = Task.WhenAll(tasks)
        whenAll.Wait()
    End Function

    Async Function DoRequest(url As String) As Task
        Dim webRequest = HttpWebRequest.Create(url)
        Using response = Await webRequest.GetResponseAsync()
            Using stream = response.GetResponseStream()
                Using reader = New StreamReader(stream)
                    Dim result = Await reader.ReadToEndAsync()
                    ' Запускаем обработку результата запроса
                    Await Task.Run(Sub
                        HandleRequestResult(result)
                    End Sub)
                End Using
            End Using
        End Using
    End Function

    Sub HandleRequestResult(result As String)
        ' Здесь какая-нибудь долгая обработка запроса
    End Function
End Module


...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025525
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Shocker.Pro
fkthat, добавь ему ConfigureAwait ))

Я что-то и не подумал, что у него может быть GUI. Но, если большую часть времени отнимает ожидание IO, то это для общей производительности некритично, т.к. основной поток все равно почти всегда будет не занят.
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025558
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
fkthat,

поменял строки
Код: vbnet
1.
2.
Sub Main(args As String())
whenAll.Wait()

на
Код: vbnet
1.
2.
Async Sub Main(args As String())
Await whenAll

а то всё виснет намертво

спасибо, теперь обработка полученного результата параллельная, а непосредственно получение ответа ведь нет? там под миллион строк, может, они удлиняют выполнение в несколько раз?
в моём представлении нужно 100 потоков, по потоку на соединение, в каждом происходит обращение, получение ответа, обработка. если так нельзя\не принято, то почему? время на создание потоков\соединений, затраченная память, изношенность процессора не играет роли, т.к. это можно сделать заранее
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025568
qlewerok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
а как считывание ответа с сервера разбить хотя бы на 4 потока? по принципу: пришёл ответ, считывается первым потоком. во время считывания пришёл второй ответ, он не прерывает/не дожидается считывания первого ответа, а считывается вторым потоком. заняты два потока - третьим. в теории это будет гениально. по сути, "многопоточное ожидание". отдельно многопоточность и отдельно ожидание теперь знаю, как делать, а вместе... подскажете?
...
Рейтинг: 0 / 0
параллельные запросы HttpWebRequest
    #40025573
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
В последнем примере HandleRequestResult запускается в отдельной задаче, то есть работают независимо т друг друга не ждут. Если только ты сам своим кодом не завязываешь их друг на друга.

Но вообще, по идее неплохо бы СНАЧАЛА разобраться, как работает многопоточность и TPL в NET, а потом уже писать какой-то многопоточный код, а не наоборот. Хотя бы разобраться на примере уже написанного кода. Ведь fkthat не будет вечно за тебя программу писать, нужно какие-то собственные знания наращивать.
...
Рейтинг: 0 / 0
25 сообщений из 67, страница 1 из 3
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / параллельные запросы HttpWebRequest
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]