Гость
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / параллельные запросы HttpWebRequest / 25 сообщений из 67, страница 1 из 3
06.12.2020, 22:37
    #40025094
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
в цикле в пуле потоков
Код: 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
06.12.2020, 23:23
    #40025101
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
Почему ты просто не используешь 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
06.12.2020, 23:47
    #40025104
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
fkthat,

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

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

есть такой код на vb.net?) пожалуйста
...
Рейтинг: 0 / 0
07.12.2020, 00:27
    #40025115
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
07.12.2020, 00:31
    #40025116
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
qlewerok
fkthat,

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

Сейчас попробовал. Он, похоже, даже C# 8 не понимает.
...
Рейтинг: 0 / 0
07.12.2020, 00:58
    #40025118
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
Ну значит ТС пусть на шарп переходит.
Я абсолютно не понимаю, как кто-то может писать на VB.NET при практически полном отсутствии статей, учебников и документации.
Даже Microsoft перестал включать в современную документацию примеры на VB.NET.
...
Рейтинг: 0 / 0
07.12.2020, 01:16
    #40025119
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
07.12.2020, 10:03
    #40025154
vb_sub
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
Сначала проверь, стоит ли вообще все в многопоток делать- может последовательно и быстрее получится конкретно в твоем случае.
...
Рейтинг: 0 / 0
07.12.2020, 10:17
    #40025156
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
vb_sub
Сначала проверь, стоит ли вообще все в многопоток делать- может последовательно и быстрее получится конкретно в твоем случае.

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

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

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

. но всё равно код выполняется больше секунды для 70 соединений, это долго. что-то явно можно улучшить, буду благодарен, если подскажете, что. и цифры 20 и 50 я брал методом тыка. если увеличивать, начинают сыпаться ошибки соединения, какие цифры должны быть и от чего зависит, я хз(
...
Рейтинг: 0 / 0
07.12.2020, 13:46
    #40025232
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
07.12.2020, 14:37
    #40025258
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
fkthat,

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

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

все три слова впервые встречаю в языке. подскажете, как будет выглядеть код без неё? можно с разложением на несколько функций, а то там одна в другой как-то... и url у меня разные, передаются как раз в args As String()
...
Рейтинг: 0 / 0
07.12.2020, 14:56
    #40025270
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
07.12.2020, 15:07
    #40025276
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
08.12.2020, 10:34
    #40025505
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
fkthat,

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

код доходит до получения ответа первого соединения и, если ответ не готов, идёт дальше создавать второе соединение. когда ответ первого соединение готов, программа останавливает выполнение действий, возвращается к первому соединению, выполняет получение ответа и обработку, идёт дальше. и если ответы двух соединений получены одновременно, программа примет их последовательно. отсюда 40 одинаковых запросов выполняются в 4 раза дольше 1 соединения. да, не в 40 за счёт асинхронных ожиданий, но всё-таки не параллельно, а каждая миллисекунда критична
...
Рейтинг: 0 / 0
08.12.2020, 11:04
    #40025519
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
fkthat, добавь ему ConfigureAwait ))
...
Рейтинг: 0 / 0
08.12.2020, 11:05
    #40025521
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
08.12.2020, 11:10
    #40025525
fkthat
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
Shocker.Pro
fkthat, добавь ему ConfigureAwait ))

Я что-то и не подумал, что у него может быть GUI. Но, если большую часть времени отнимает ожидание IO, то это для общей производительности некритично, т.к. основной поток все равно почти всегда будет не занят.
...
Рейтинг: 0 / 0
08.12.2020, 13:04
    #40025558
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
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
08.12.2020, 13:34
    #40025568
qlewerok
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
а как считывание ответа с сервера разбить хотя бы на 4 потока? по принципу: пришёл ответ, считывается первым потоком. во время считывания пришёл второй ответ, он не прерывает/не дожидается считывания первого ответа, а считывается вторым потоком. заняты два потока - третьим. в теории это будет гениально. по сути, "многопоточное ожидание". отдельно многопоточность и отдельно ожидание теперь знаю, как делать, а вместе... подскажете?
...
Рейтинг: 0 / 0
08.12.2020, 13:43
    #40025573
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
параллельные запросы HttpWebRequest
В последнем примере HandleRequestResult запускается в отдельной задаче, то есть работают независимо т друг друга не ждут. Если только ты сам своим кодом не завязываешь их друг на друга.

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


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