Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.50/40: Рейтинг темы: голосов - 40, средняя оценка - 4.50
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825

Очередь запросов

11.09.2018, 23:26. Показов 8556. Ответов 44
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, форумчане. Такой вопрос.. Есть софтина, которая обращается к апи одно сервиса, из месяца в месяц обрастала функционалом, когда-то хватало выставить дефолт таймаут между запросами, потом было прикручено регулирование таймаута, но сейчас уже и этого не хватает, т.к из разных функций и потоков, отправляет запросы и таймауты уже не помогают регулировать кол-во запросов в секунду. Из-за превышения ключ сносит, что доставляет небольшой дискомфорт пользователям.
Суть вопроса в том, как сделать какую нибудь очередь запросов в одном месте, чтобы регулировать кол-во отправленных запросов таймаутом из одного места? Надеюсь вы меня поняли.. Для запросов использую xNet
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
11.09.2018, 23:26
Ответы с готовыми решениями:

Очередь выполнения множества запросов и рано или поздно наступающий StackOverflow
Вообщем имеется очередь выполнения: в очередь кладется команда (например, выполнение sql запроса) и потом в 1 потоке выполняются все...

Web api Управлять очередью запросов динамически (длиной) и как получить url поступившего в очередь запроса
Я так понимаю, что все запросы приходят в HTTP.Sys откуда запрос в виде HTTP.Context поступает на web api. И все параметры HTTP.Sys нужно...

Очередь запросов и их выполнение
Привет, есть метод вида void task(int number), и к нему делаются асинхронные запросы, но из-за свой особенности он не асинхронный и сделать...

44
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
17.09.2018, 19:14  [ТС]
Студворк — интернет-сервис помощи студентам
fan92rus, да, будет не плохо и для меня и для людей, которым может понадобиться
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
17.09.2018, 21:34
Цитата Сообщение от Usaga Посмотреть сообщение
в приложении будет висеть N заблокированных потоков.
SemaphoreSlim умеет в асинхронное ожидание.
Цитата Сообщение от Usaga Посмотреть сообщение
Т.е. порядок исполнения запросов будет неопределён
В вашем примере он тоже не определён, хоть и "честнее". Для пущей честности можно флаг PreferFairness выставлять, но и он ничего не гарантирует.

Ещё бы не плохо поддержку асинхронного апи запилить, но для xNet это не актуально.
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
17.09.2018, 21:39  [ТС]
TopLayer, это как? Почему не гарантирован ? Там вроде-бы берутся по очереди запросы, разве нет?
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
17.09.2018, 21:42
MakcPletnev, они по очереди отправляются в пул потоков. А в каком порядке они там выполнятся - не определено.
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
17.09.2018, 21:48  [ТС]
TopLayer, как это можно исправить?

Добавлено через 3 минуты
TopLayer, если будет время, не откажусь от примера. Будем собирать тут все, связанное с данной темой. В гугле такого я не нашел
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
17.09.2018, 21:49
MakcPletnev, не пытаться выполнять запросы одновременно.
C#
1
2
        // Можно сделать конфигурируемой настройкой
        private const int MaxParallelTasks = 1;
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
17.09.2018, 21:51  [ТС]
TopLayer, ну по сути тогда будет чисто залипание всех запросов до момента ответа от первого, это не очень хорошая концепция. У нас есть разрешение отправлять ~5 в секунду, т.е каждые 200мс можно отправлять следующий
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
17.09.2018, 22:03
MakcPletnev, если отправить второй запрос не дождавшись результата первого, то не будет никаких гарантий, что сначала выполнится первый запрос, а потом второй.
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
17.09.2018, 22:09  [ТС]
TopLayer, а мне это не нужно, я отправлю второй запрос из одной функции, когда будет известен результат первого, в любом случае. Хотя все таки хотелось бы , чтобы все таки работало по принципу очереди.. Можно это сделать, без "однопоточности"?
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
18.09.2018, 00:05
MakcPletnev, такое вам нужно?
Кликните здесь для просмотра всего текста
C#
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
void Main()
{
    using (var innerPool = new LimitedConcurrencyThreadPool(maxConcurrency: 5))
    {
        var sync = new CountdownEvent(initialCount: 50);
        
        var pool = new ThrottlingThreadPool(innerPool, maxItemsInPeriod: 5, period: TimeSpan.FromSeconds(1.01));
        
        var stopwatch = Stopwatch.StartNew();
        object locker = new object();
        
        for (int i = 0; i < 50; i++)
        {
            var temp = i;
            pool.Enqueue(() =>
            {
                lock (locker)
                {
                    Console.WriteLine($"{temp,2}: {stopwatch.Elapsed}");
                }
                
                // API call
                Thread.Sleep(150);
                
                sync.Signal();
            });
        }
        
        sync.Wait();
    }
}
 
interface IThreadPool
{
    void Enqueue(Action item);
}
 
class LimitedConcurrencyThreadPool : IThreadPool, IDisposable
{
    private readonly List<Thread> Threads = new List<Thread>();
    private readonly BlockingCollection<Action> Items = new BlockingCollection<Action>();
    private readonly object Locker = new object();
    private volatile int _currentConcurrency;
    
    public int MaxConcurrency { get; }
    
    public LimitedConcurrencyThreadPool(int maxConcurrency)
    {
        if (maxConcurrency <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
        }
        MaxConcurrency = maxConcurrency;
    }
    
    public void Enqueue(Action item)
    {
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item));
        }
 
        Items.Add(item);
 
        lock (Locker)
        {
            if (_currentConcurrency + Items.Count > Threads.Count && Threads.Count < MaxConcurrency)
            {
                Threads.Add(new Thread(Run) { IsBackground = true });
                Threads.Last().Start();
            }
        }
    }
    
    private void Run()
    {
        foreach (var item in Items.GetConsumingEnumerable())
        {
            Interlocked.Increment(ref _currentConcurrency);
            item();
            Interlocked.Decrement(ref _currentConcurrency);
        }
    }
    
    public void Dispose()
    {
        Items.CompleteAdding();
    }
}
 
class ThrottlingThreadPool : IThreadPool
{
    private readonly object Locker = new object();
    private readonly Stopwatch Stopwatch = Stopwatch.StartNew();
    private readonly Queue<TimeSpan> Timestamps = new Queue<TimeSpan>();
    private readonly IThreadPool InnerThreadPool;
    
    public int MaxItemsInPeriod { get; }
    public TimeSpan Period { get; }
    
    public ThrottlingThreadPool(IThreadPool innerThreadPool, int maxItemsInPeriod, TimeSpan period)
    {
        if (innerThreadPool == null)
        {
            throw new ArgumentNullException(nameof(innerThreadPool));
        }
        if (maxItemsInPeriod <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxItemsInPeriod));
        }
        if (period <= TimeSpan.FromSeconds(0))
        {
            throw new ArgumentOutOfRangeException(nameof(period));
        }
        
        InnerThreadPool = innerThreadPool;
        MaxItemsInPeriod = maxItemsInPeriod;
        Period = period;
    }
 
    public void Enqueue(Action item)
    {
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item));
        }
        InnerThreadPool.Enqueue(() => Throttle(item));
    }
    
    private void Throttle(Action item)
    {
        TimeSpan toWait;
        TimeSpan timestamp;
        
        lock (Locker)
        {
            timestamp = Stopwatch.Elapsed;
            
            while (Timestamps.Any() && Timestamps.Peek() < timestamp - Period)
            {
                Timestamps.Dequeue();
            }
            
            if (Timestamps.Count < MaxItemsInPeriod)
            {
                toWait = TimeSpan.FromSeconds(0);
            }
            else
            {
                toWait = Timestamps.ElementAt(Timestamps.Count - MaxItemsInPeriod) + Period - timestamp;
            }
            Timestamps.Enqueue(timestamp + toWait);
        }
 
        if (toWait > TimeSpan.FromSeconds(0))
        {
            Thread.Sleep(toWait);
        }
        item();
    }
}
1
Эксперт .NET
 Аватар для Usaga
14784 / 9558 / 1366
Регистрация: 21.01.2016
Сообщений: 36,046
18.09.2018, 06:45
Цитата Сообщение от TopLayer Посмотреть сообщение
В вашем примере он тоже не определён, хоть и "честнее".
Задачи выгребаются из очереди в том порядке, в каком они поступали в неё. Так что порядок определён.

Цитата Сообщение от TopLayer Посмотреть сообщение
SemaphoreSlim умеет в асинхронное ожидание.
Речь не о механизмах ожидания, а о регулировании самого запуска задач. Какой смысл запускать задачу, про которую известно, что она упрётся в блокировку?
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
18.09.2018, 14:17  [ТС]
Usaga, TopLayer, так все же?) Кто прав?
0
Эксперт .NET
 Аватар для Usaga
14784 / 9558 / 1366
Регистрация: 21.01.2016
Сообщений: 36,046
18.09.2018, 14:22
Лучший ответ Сообщение было отмечено MakcPletnev как решение

Решение

MakcPletnev, мой вариант держит запущенными не более N задач. Остальные ждут запуска в очереди. Исполнение в порядке поступления задач (очередь же). Варианты с локами и семафорами подразумевают, что задачи висят запущенными все до единой, но упираются в локи\семафоры и разблокируются в неопределённом порядке.

Какой вариант вам больше подходит, тот и выбирайте. Но лично мне очень не нравится ситуация с "висящими" на локах потоках. Неэффективное расходование ресурсов.
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
18.09.2018, 14:24  [ТС]
Usaga, я про вариант TopLayer , он сделал что-то похожее на ваше решение, только сложнее на мой взляд. И я вот не понимаю, чем его реализация лучше, если выполняется по сути тоже самое..
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
18.09.2018, 14:31
Лучший ответ Сообщение было отмечено MakcPletnev как решение

Решение

Цитата Сообщение от MakcPletnev Посмотреть сообщение
Кто прав?
Мы особо и не спорили. Тут больше о формулировках.
Цитата Сообщение от MakcPletnev Посмотреть сообщение
выполняется по сути тоже самое..
Мой код делает то, что вам нужно - ограничивает кол-во запросов в секунду. В варианте Usaga за секунду хоть 100 запросов могут быть выполнены.
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
18.09.2018, 14:34  [ТС]
TopLayer, да , я уже понял это. Просто до этого мы говорили за очередность запросов, хотя может я просто не так понял о чем вы пытались сказать. В любом случае, всем спасибо) Буду использовать, думаю очень хорошую базу сделали)
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
18.09.2018, 14:41
Цитата Сообщение от MakcPletnev Посмотреть сообщение
мы говорили за очередность запросов,
Простая мысль: если вы запустили несколько операций параллельно, то они могут быть выполнены в любом порядке.
0
Эксперт .NET
 Аватар для Usaga
14784 / 9558 / 1366
Регистрация: 21.01.2016
Сообщений: 36,046
18.09.2018, 14:43
MakcPletnev, да, я провтыкал условие про количество запросов в секунду. Мой вариант действительно на время не подвязан, только на количество одновременных задач.
0
907 / 664 / 318
Регистрация: 23.10.2016
Сообщений: 1,543
18.09.2018, 15:28
Лучший ответ Сообщение было отмечено MakcPletnev как решение

Решение

MakcPletnev, ну и поскольку блокирующие вызовы xNet будут находится в изолированном пуле потоков, то вам более не следует писать блокирующий код, так как механизм async/await предлагает более хорошую альтернативу. То есть окончательно переезжаем на модный TPL.
Кликните здесь для просмотра всего текста
C#
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
class Api
{
    public static string DownloadString(int id)
    {
        Thread.Sleep(500);
        return $"This string was downloaded from the Internet by id = {id}";
    }
}
 
async Task Main()
{
    using (var threadPool = new LimitedConcurrencyThreadPool(maxConcurrency: 5))
    {
        var pool = new ThrottlingThreadPool(threadPool, maxItemsInPeriod: 5, period: TimeSpan.FromSeconds(1.01));
        
        var stopwatch = Stopwatch.StartNew();
        object locker = new object();
        
        var factory = new TaskFactory(new CustomThreadPoolTaskScheduler(pool));
        var tasks = new List<Task<string>>();
 
        for (int i = 0; i < 50; i++)
        {
            var temp = i;
            tasks.Add(factory.StartNew(() =>
            {
                lock (locker)
                {
                    Console.WriteLine($"{temp,2} {stopwatch.Elapsed}");
                }
                return Api.DownloadString(temp);
            }));
        }
        
        // используем результат какой-нибудь задачи, как только он будет готов
        Console.WriteLine(await tasks[28]);
        
        // дожидаемся выполнения всех задач
        await Task.WhenAll(tasks);
    }
}
 
interface IThreadPool
{
    void Enqueue(Action item);
}
 
class LimitedConcurrencyThreadPool : IThreadPool, IDisposable
{
    private readonly List<Thread> Threads = new List<Thread>();
    private readonly BlockingCollection<Action> Items = new BlockingCollection<Action>();
    private readonly object Locker = new object();
    private volatile int _currentConcurrency;
    
    public int MaxConcurrency { get; }
    
    public LimitedConcurrencyThreadPool(int maxConcurrency)
    {
        if (maxConcurrency <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxConcurrency));
        }
        MaxConcurrency = maxConcurrency;
    }
    
    public void Enqueue(Action item)
    {
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item));
        }
 
        Items.Add(item);
 
        lock (Locker)
        {
            if (_currentConcurrency + Items.Count > Threads.Count && Threads.Count < MaxConcurrency)
            {
                Threads.Add(new Thread(Run) { IsBackground = true });
                Threads.Last().Start();
            }
        }
    }
    
    private void Run()
    {
        foreach (var item in Items.GetConsumingEnumerable())
        {
            Interlocked.Increment(ref _currentConcurrency);
            item();
            Interlocked.Decrement(ref _currentConcurrency);
        }
    }
    
    public void Dispose()
    {
        Items.CompleteAdding();
    }
}
 
class ThrottlingThreadPool : IThreadPool
{
    private readonly object Locker = new object();
    private readonly Stopwatch Stopwatch = Stopwatch.StartNew();
    private readonly Queue<TimeSpan> Timestamps = new Queue<TimeSpan>();
    private readonly IThreadPool InnerThreadPool;
    
    public int MaxItemsInPeriod { get; }
    public TimeSpan Period { get; }
    
    public ThrottlingThreadPool(IThreadPool innerThreadPool, int maxItemsInPeriod, TimeSpan period)
    {
        if (innerThreadPool == null)
        {
            throw new ArgumentNullException(nameof(innerThreadPool));
        }
        if (maxItemsInPeriod <= 0)
        {
            throw new ArgumentOutOfRangeException(nameof(maxItemsInPeriod));
        }
        if (period <= TimeSpan.FromSeconds(0))
        {
            throw new ArgumentOutOfRangeException(nameof(period));
        }
        
        InnerThreadPool = innerThreadPool;
        MaxItemsInPeriod = maxItemsInPeriod;
        Period = period;
    }
 
    public void Enqueue(Action item)
    {
        if (item == null)
        {
            throw new ArgumentNullException(nameof(item));
        }
        InnerThreadPool.Enqueue(() => Throttle(item));
    }
    
    private void Throttle(Action item)
    {
        TimeSpan toWait = TimeSpan.FromSeconds(0);
 
        lock (Locker)
        {
            var timestamp = Stopwatch.Elapsed;
            
            while (Timestamps.Any() && Timestamps.Peek() < timestamp - Period || Timestamps.Count > MaxItemsInPeriod)
            {
                Timestamps.Dequeue();
            }
            
            if (Timestamps.Count == MaxItemsInPeriod)
            {
                toWait = Timestamps.Peek() + Period - timestamp;
            }
            Timestamps.Enqueue(timestamp + toWait);
        }
 
        if (toWait > TimeSpan.FromSeconds(0))
        {
            Thread.Sleep(toWait);
        }
        item();
    }
}
 
class CustomThreadPoolTaskScheduler : TaskScheduler
{
    private readonly IThreadPool ThreadPool;
    
    public CustomThreadPoolTaskScheduler(IThreadPool threadPool)
    {
        if (threadPool == null)
        {
            throw new ArgumentNullException(nameof(threadPool));
        }
        ThreadPool = threadPool;
    }
    
    protected override IEnumerable<Task> GetScheduledTasks()
    {
        return new Task[0];
    }
 
    protected override void QueueTask(Task task)
    {
        ThreadPool.Enqueue(() => TryExecuteTask(task));
    }
 
    protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
    {
        return false;
    }
}
1
41 / 37 / 9
Регистрация: 01.02.2014
Сообщений: 825
19.09.2018, 01:12  [ТС]
TopLayer, прямо до идеала довели) Спасибо большое, в ближайшее время разберусь как это работает и внедрю к себе)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
19.09.2018, 01:12

Очередь отправки get-запросов
Есть get запрос: http://158.4581/sad.php?id=&amp;auth= И есть содержимое в richTextBox1 такого типа: ...

Разработка модели обследования запросов (процессов) с использованием дисциплины, типа Очередь
Разработка модели обследования запросов (процессов) с помощью дисциплины, типа Очередь

Очередь XML запросов
Доброе время суток. Задача: выполнить очередь XML запросов, причем так, чтобы страница была доступна для &quot;кликания&quot; во время...

Сформировать очередь по файлу целых чисел. Промоделировать очередь в супермаркете
Сформировать очередь по файлу целых чисел. Промоделировать очередь в супермаркете. В каждый момент времени происходит одно из событий:...

Очередь (сделать очередь, чтобы добавляло, удаляло, читало. Не STL.)
Помогите пожалуйста написать очередь. Есть Температура double и ее тип int ну и нужно сделать очередь, чтобы добавляло, удаляло, читало....


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
40
Ответ Создать тему
Новые блоги и статьи
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
Мобильное приложение ColorStep
pavlinmavlin 17.09.2026
Реализовал приложение Красный, Зеленый, Синий в Unity3d + c#. Название изменил на ColorStep. Приложение прошло модерацию и теперь доступно для скачивания. Делал его сам, шаг за шагом — и вот,. . .
Запрет дублирования строк в табличной части
Maks 13.09.2026
Реализация из решения ниже выполнена на нетиповом справочнике "Нормы ТО" с табличной часть "Виды ТО", разработанного в КА2, со следующими реквизитами: - ВидТО (СправочникСсылка. ВидыТО); - ВидГСМ. . .
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр.
Jin X 06.09.2026
Скрипты Tampermonkey для CyberForum, ChatGPT, Claude и пр. Работая с форумом и нейросетями в браузере часто хочется что-то подкорректировать или добавить какого-то функционала. Ниже прикреплён. . .
Программа опроса у.з. расходомера SLS-720F
Argus19 02.09.2026
Программа опроса у. з. расходомера SLS-720F Программа опрашивает один раз в минуту три ультразвуковых расходомера SLS-720F через интерфейс RS-485 по протоколу Modbus RTU. Опрашиваются регистры. . .
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru