Ответ: qp будет 250, если вы на машине, где int
- 4 байта.
Расчет:
q - p = 1000 1000/4 (размер int) = 250
Идея:
Идея арифметики указателя заключается в том, что если у вас есть указатель int
на 1000 и указатель int
до 2000, и попросите разницу, вы не спрашиваете, что такое 2000-1000. Что вы спрашиваете, сколько int
можно установить между ними.
Это очень удобно для всех видов операций, например:
int *i = 100;
i++; // This is **not** 101, it is 104, cause you actually want the next place an int could fit in memory.
Это особенно полезно при работе с массивами. Массив ints (определенный int arr[10]
) в основном обрабатывается как указатель. Когда вы пишете arr[5]
, компилятор переводит его на *(arr + 5)
, т. Е. Добавляет 5 к указателю int
с именем arr
и получает значение по этому адресу.
Причина, по которой это работает , потому что arr + 5
не означает «добавить 5 к значению arr», это означает «добавить все, что является neceassary к значению arr, чтобы идти вперед 5 int
s» или, точнее, «добавить 5 * sizeof(int)
до значения arr "
Здесь самый простой алгоритм , если Вы хотите только отбросить сообщения, когда они прибывают слишком быстро (вместо того, чтобы ставить их в очередь, который имеет смысл, потому что очередь могла бы стать произвольно многочисленной):
rate = 5.0; // unit: messages
per = 8.0; // unit: seconds
allowance = rate; // unit: messages
last_check = now(); // floating-point, e.g. usec accuracy. Unit: seconds
when (message_received):
current = now();
time_passed = current - last_check;
last_check = current;
allowance += time_passed * (rate / per);
if (allowance > rate):
allowance = rate; // throttle
if (allowance < 1.0):
discard_message();
else:
forward_message();
allowance -= 1.0;
нет никаких datastructures, таймеры и т.д. в этом решении, и оно работает чисто:) Для наблюдения этого 'допуск' выращивает на скорости 5/8 единицы в секунды самое большее, т.е. самое большее пять единиц в восемь секунд. Каждое сообщение, которое передается, вычитает одну единицу, таким образом, Вы не можете отправить больше чем пять сообщений в каждые восемь секунд.
Примечание, которое rate
должно быть целым числом, т.е. без ненулевой десятичной части или алгоритма, не будет работать правильно (фактический уровень не будет rate/per
). Например, rate=0.5; per=1.0;
не работает, потому что allowance
никогда не будет расти до 1,0. Но rate=1.0; per=2.0;
хорошо работает.
Используйте этого декоратора @RateLimited (ratepersec) перед Вашей функцией, которая ставит в очередь.
В основном, это проверяет, передали ли 1/уровень secs с прошлого раза, когда и в противном случае ожидает остаток времени, иначе он не ожидает. Это эффективно ограничивает Вас уровнем/секунда. Декоратор может быть применен к любой функции, которую Вы хотите ограниченный уровнем.
В Вашем случае, если Вы хотите максимум 5 сообщений в 8 секунд, @RateLimited использования (0.625) перед Вашей функцией sendToQueue.
import time
def RateLimited(maxPerSecond):
minInterval = 1.0 / float(maxPerSecond)
def decorate(func):
lastTimeCalled = [0.0]
def rateLimitedFunction(*args,**kargs):
elapsed = time.clock() - lastTimeCalled[0]
leftToWait = minInterval - elapsed
if leftToWait>0:
time.sleep(leftToWait)
ret = func(*args,**kargs)
lastTimeCalled[0] = time.clock()
return ret
return rateLimitedFunction
return decorate
@RateLimited(2) # 2 per second at most
def PrintNumber(num):
print num
if __name__ == "__main__":
print "This should print 1,2,3... at about 2 per second."
for i in range(1,100):
PrintNumber(i)
Сохраните время, когда последние пять строк были отправлены. Держите сообщения с очередями до времени пятое новое сообщение (если оно существует), наименьшее количество 8 секунд в прошлом (с last_five как массив времен):
now = time.time()
if len(last_five) == 0 or (now - last_five[-1]) >= 8.0:
last_five.insert(0, now)
send_message(msg)
if len(last_five) > 5:
last_five.pop()
Одно решение состоит в том, чтобы присоединить метку времени к каждому объекту очереди и отбрасывать объект после того, как 8 секунд передали. Можно выполнить эту проверку каждый раз, когда очередь добавляется к.
Это только работает, если Вы ограничиваете размер очереди 5 и отбрасываете какие-либо дополнения, пока очередь полна.
(rows<oldRows)||(cols<oldCols)
. Должен использовать Min(rows,oldRows)
в цикле.
– CodesInChaos
30 June 2011 в 18:57
Маркерный Блок довольно прост реализовать.
Запускаются с блока с 5 маркерами.
Каждый 5/8 секунды: Если блок имеет меньше чем 5 маркеров, добавьте тот.
Каждый раз Вы хотите отправить сообщение: Если блок имеет маркер ≥1, выньте один маркер и отправьте сообщение. Иначе ожидайте/отбрасывайте сообщение/независимо от того, что.
(очевидно, в фактическом коде, Вы использовали бы целочисленный счетчик вместо реальных маркеров и можно оптимизировать каждый шаг 5/8s путем хранения меток времени)
<час>Чтение вопроса снова, если ограничение скорости полностью сбрасывается каждые 8 секунд, то вот модификация:
Запускаются с метки времени, last_send
, за один раз давно (например, в эпоху). Кроме того, запустите с того же блока с 5 маркерами.
Забастовка каждое 5/8 правило секунд.
Каждый раз Вы отправляете сообщение: Во-первых, проверьте если last_send
≥ 8 секунд назад. Если так, заполнитесь, блок (установите его на 5 маркеров). Во-вторых, если существуют маркеры в блоке, отправьте сообщение (иначе, отбрасывать/ожидать/и т.д.). В-третьих, установите last_send
на теперь.
, Который должен работать на тот сценарий.
<час>я на самом деле записал бота IRC с помощью стратегии как это (первый подход). В Perl, не Python, но вот является некоторым кодом для иллюстрирования:
первая часть здесь обрабатывает добавляющие маркеры к блоку. Вы видите оптимизацию добавляющих маркеров на основе времени (2-й для длительности строки), и затем последняя строка фиксирует содержание блока к максимуму (MESSAGE_BURST)
my $start_time = time;
...
# Bucket handling
my $bucket = $conn->{fujiko_limit_bucket};
my $lasttx = $conn->{fujiko_limit_lasttx};
$bucket += ($start_time-$lasttx)/MESSAGE_INTERVAL;
($bucket <= MESSAGE_BURST) or $bucket = MESSAGE_BURST;
, $conn является структурой данных, которая роздана. Это в методе, который обычно работает (он вычисляет, когда в следующий раз он будет иметь что-то, чтобы сделать и спит или что долго или пока это не получает сетевой трафик). Следующая часть метода обрабатывает отправку. Это скорее сложно, потому что сообщениям связали приоритеты с ними.
# Queue handling. Start with the ultimate queue.
my $queues = $conn->{fujiko_queues};
foreach my $entry (@{$queues->[PRIORITY_ULTIMATE]}) {
# Ultimate is special. We run ultimate no matter what. Even if
# it sends the bucket negative.
--$bucket;
$entry->{code}(@{$entry->{args}});
}
$queues->[PRIORITY_ULTIMATE] = [];
Это - первая очередь, которая выполняется несмотря ни на что. Даже если это уничтожило наше соединение для лавинной рассылки. Используемый для чрезвычайно важных вещей, как ответ на PING сервера. Затем, остальная часть очередей:
# Continue to the other queues, in order of priority.
QRUN: for (my $pri = PRIORITY_HIGH; $pri >= PRIORITY_JUNK; --$pri) {
my $queue = $queues->[$pri];
while (scalar(@$queue)) {
if ($bucket < 1) {
# continue later.
$need_more_time = 1;
last QRUN;
} else {
--$bucket;
my $entry = shift @$queue;
$entry->{code}(@{$entry->{args}});
}
}
}
Наконец, состояние блока сохраняется назад к структуре данных $conn (на самом деле немного позже в методе; это сначала вычисляет, как скоро это будет иметь больше работы)
# Save status.
$conn->{fujiko_limit_bucket} = $bucket;
$conn->{fujiko_limit_lasttx} = $start_time;
, Как Вы видите, фактический код обработки блока является очень маленьким — приблизительно четыре строки. Остальная часть кода является приоритетной обработкой очереди. Бот имеет приоритетные очереди так, чтобы, например, кто-то болтающий с ним не мог препятствовать тому, чтобы он делал свои важные обязанности удара/запрета.
Как насчет этого:
long check_time = System.currentTimeMillis();
int msgs_sent_count = 0;
private boolean isRateLimited(int msgs_per_sec) {
if (System.currentTimeMillis() - check_time > 1000) {
check_time = System.currentTimeMillis();
msgs_sent_count = 0;
}
if (msgs_sent_count > (msgs_per_sec - 1)) {
return true;
} else {
msgs_sent_count++;
}
return false;
}