Используйте этого декоратора @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)
имеет смысл разрешить связывание let внутри размеченных объединений. Я думаю, что причина, по которой это невозможно, заключается в том, что размеченные союзы все еще основаны на дизайне OCaml, а объекты - из мира .NET. F # пытается максимально интегрировать эти два аспекта, но он, вероятно, может пойти дальше.
В любом случае, мне кажется, что вы используете дискриминационное объединение только для реализации некоторого внутреннего поведения AI_Choose
] тип. В этом случае вы можете объявить размеченное объединение отдельно и использовать его для реализации типа объекта.
Думаю, вы могли бы написать что-то вроде этого:
type AiChooseOptions =
| AI_Priority of list<AI> * Condition
| AI_Weighted_Priority of list<AI * float> * Condition
type AiChoose(aiOptions) =
let mutable chosen = Option<AI>.None
member this.Choose() =
match aiOptions with
| AI_Priority(aiList, condition) -> (...)
| AI_Weighted_Priority(aiList, condition) -> (...)
member this.Chosen (...)
interface AI with (...)
Ключевое различие между иерархией классов и размеченными союзами заключается в расширяемости.
Для всех, кого это интересует, я в итоге получил AI_Priority
и AI_Weighted_Priority
из абстрактного базового класса.
[<AbstractClass>]
type AI_Choose() =
let mutable chosen = Option<AI>.None
abstract member Choose : unit -> AI
member this.Chosen
with get() =
if Option.isNone chosen then
chosen <- Some(this.Choose())
chosen.Value
and set(x) =
if Option.isSome chosen then
chosen.Value.Stop()
chosen <- Some(x)
x.Start()
interface AI with
member this.Start() =
this.Chosen.Start()
member this.Stop() =
this.Chosen.Stop()
member this.Reset() =
this.Chosen <- this.Choose()
member this.Priority() =
this.Chosen.Priority()
member this.Update(gameTime) =
this.Chosen.Update(gameTime)
type AI_Priority(aiList : list<AI>, condition : Condition) =
inherit AI_Choose()
override this.Choose() =
aiList
|> List.map (fun ai -> ai, ai.Priority())
|> condition.Select
|> fst
type AI_Weighted_Priority(aiList : list<AI * float>, condition : Condition) =
inherit AI_Choose()
override this.Choose() =
aiList
|> List.map (fun (ai, weight) -> ai, weight * ai.Priority())
|> condition.Select
|> fst
Вернувшись к этому коду, я в итоге принял предложение Томаса, которое оказалось намного чище.
type AiChooseOptions =
| Priority of List<AI * Priority>
| WeightedPriority of List<AI * Priority * float>
member this.Choose(condition : Condition) =
match this with
| Priority(list) ->
list
|> List.map (fun (ai, priority) -> ai, priority.Priority())
|> condition.Select
| WeightedPriority(list) ->
list
|> List.map (fun (ai, p, weight) -> ai, p.Priority() * weight)
|> condition.Select
type AiChoose(condition, list : AiChooseOptions ) =
let mutable chosen = Unchecked.defaultof<AI>, 0.0
interface AI with
member this.Update(gameTime) =
(fst chosen).Update(gameTime)
interface Priority with
member this.Priority() =
chosen <- list.Choose(condition)
(snd chosen)