#队列 #框架 #算法 #Web框架 #网络 #Web

bin+lib qframework

一个基于队列模型,以清晰设计为目标的实验性微框架。

3个版本

0.1.2 2019年8月8日
0.1.1 2019年8月8日
0.1.0 2019年8月7日

#742 in 算法

MIT/Apache

145KB
789

包含 (Mach-o可执行文件, 370KB) fib

Q

Q框架基于一个实验性模拟器,如您在初始代码中所见。虽然它是咖啡崩溃和24小时不睡觉思考的结果,但我还是要感谢其原始创作者

形式定义

队列自动机可以定义为六元组

  • M = ( Q , Σ , Γ , $ , s , δ ) 其中
  • Q 是状态集合;
  • Σ ⊂ Γ 是输入字母表集合;
  • Γ 是队列字母表;
  • $ ∈ Γ − Σ 是初始队列符号;
  • s ∈ Q 是起始状态;
  • δ : Q × Γ → Q × Γ ∗ 是转换函数。

但最有趣的是,它是图灵完备的!

理论

我们可以将队列自动机映射到一个由

  • 基于事件的离散事件模拟器
  • 队列网络

队列网络本身是一个非常强大的工具,可以模拟包括网络、Web服务、计算机架构在内的许多系统。基于事件的离散事件模拟器可以以较低的成本“执行”此类模型。

将它们结合起来,我们得到了一个非常强大的工具,适用于几乎所有的领域。

演示1: demo.rs

demo.rs是一个简单的D/D/1模拟器,它可以调整以模拟任何M/G/1或任何网络模型,但在这里我们将其用作调度器。生成器可以被认为是事件源,服务器可以被认为是事件接收器。

$cargo run
   Compiling qframework v0.1.0 (/Users/mark/Project/q)
    Finished dev [unoptimized + debuginfo] target(s) in 0.32s
     Running `target/debug/demo`
@0000000000 sending  [customor 0000] 	total tx 0
@0000000001 serving  [customor 0000] 	total rx 1
@0000000001 sending  [customor 0001] 	total tx 1
@0000000002 serving  [customor 0001] 	total rx 2
@0000000002 sending  [customor 0002] 	total tx 2
@0000000003 serving  [customor 0002] 	total rx 3
@0000000003 sending  [customor 0003] 	total tx 3
@0000000004 serving  [customor 0003] 	total rx 4
@0000000004 sending  [customor 0004] 	total tx 4
@0000000005 serving  [customor 0004] 	total rx 5
@0000000005 Finished All Events
Send 5, processed 5, tick 5

如果服务器忙碌,则允许服务器丢弃请求,这可以通过在服务器代码上提前2个时钟周期轻松验证。

@0000000021 dropped  [customor 0021]
@0000000022 serving  [customor 0019] 	total rx 11
@0000000022 sending  [customor 0022] 	total tx 22
@0000000023 sending  [customor 0023] 	total tx 23
@0000000023 dropped  [customor 0023]
@0000000024 serving  [customor 0020] 	total rx 12
@0000000024 sending  [customor 0024] 	total tx 24
@0000000025 sending  [customor 0025] 	total tx 25

演示2: fib.rs

如果这样一个强大的工具只能处理Web请求或模拟队列网络,那就太遗憾了。由于它是图灵完备的,我们可以做更多高级的事情。比如尾递归优化和递归,以及惰性求值?Rust中还有哪些缺失的东西!

是的。

让我们回到旧的fib(n)函数,看看如何在q框架中实现它!

首先我们定义一个名为Fib的东西,另一个名为Add的东西

Fib(n) = Add ( Fib(n -1 ) , Fib (n-2), Fib(0) = 0, Fib(1) = 1。

1:开始 - 将 Event::Fib(8) 添加到事件队列 2:系统启动,选择第一个事件,运行 fib.execute() 3:在 fib.execute() 内部,它只是将 3 个事件添加到列表中:Fib(6)、Fib(7)、Add,现在 Fib(8) 事件已消失,记住我们并没有复制 Fib,只是传递一个 Event 类型 Fib(8)。 4:在 fib.execute() 被调用后,系统从优先队列(已排序)中选择最近的事件,这次是 Fib(6)。 5:Fib(6) 将 3 个事件添加到列表中,现在变为 Fib(7)、Add、Fib(5)、Fib(4)。 6:尝试运行 Add,但我们发现它的队列(只有当我们在其缓冲区中找到两个或更多数字时才执行加法)为空,我们将其推回到事件队列的末尾。 7:重复进行,最终我们得到 Fib(0)、Fib(1)、Add,在 Fib(0) 和 Fib(1) 上,我们将数字写入 Add 的队列。 8:最终 Add 将被执行,它弹出一个数字,将它们相加并将结果推回到它的队列。 9:最终我们在 Add 的队列中有了最后两个数字,并将它们相加,再次将结果写入 Add 的队列。 10:系统中没有更多事件,我们得到了 Add 队列中的结果。

./fib 5
@0000000000 queue = Queue { fibs: [], capacity: 1000 }
@0000000001 queue = Queue { fibs: [], capacity: 1000 }
@0000000002 queue = Queue { fibs: [], capacity: 1000 }
@0000000003 queue = Queue { fibs: [], capacity: 1000 }
@0000000004 queue = Queue { fibs: [], capacity: 1000 }
@0000000005 queue = Queue { fibs: [1], capacity: 1000 }
@0000000006 queue = Queue { fibs: [1], capacity: 1000 }
@0000000007 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000008 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000009 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000010 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000011 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000011 queue = Queue { fibs: [1, 1], capacity: 1000 }
@0000000012 queue = Queue { fibs: [2], capacity: 1000 }
@0000000013 queue = Queue { fibs: [2, 1], capacity: 1000 }
@0000000014 queue = Queue { fibs: [2, 1], capacity: 1000 }
@0000000014 queue = Queue { fibs: [2, 1], capacity: 1000 }
@0000000015 queue = Queue { fibs: [3], capacity: 1000 }
@0000000015 queue = Queue { fibs: [3], capacity: 1000 }
@0000000016 queue = Queue { fibs: [3, 0], capacity: 1000 }
@0000000017 queue = Queue { fibs: [3, 0], capacity: 1000 }
@0000000017 queue = Queue { fibs: [3, 0], capacity: 1000 }
@0000000018 queue = Queue { fibs: [3], capacity: 1000 }
@0000000018 queue = Queue { fibs: [3, 0], capacity: 1000 }
@0000000019 queue = Queue { fibs: [3], capacity: 1000 }
@0000000020 queue = Queue { fibs: [3, 1], capacity: 1000 }
@0000000021 queue = Queue { fibs: [3, 1], capacity: 1000 }
@0000000022 queue = Queue { fibs: [3, 1], capacity: 1000 }
@0000000022 queue = Queue { fibs: [3, 1], capacity: 1000 }
@0000000023 queue = Queue { fibs: [4], capacity: 1000 }
@0000000023 queue = Queue { fibs: [4, 1], capacity: 1000 }
@0000000024 queue = Queue { fibs: [5], capacity: 1000 }
@0000000025 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000026 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000026 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000027 queue = Queue { fibs: [5], capacity: 1000 }
@0000000027 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000028 queue = Queue { fibs: [5], capacity: 1000 }
@0000000029 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000030 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000030 queue = Queue { fibs: [5, 0], capacity: 1000 }
@0000000031 queue = Queue { fibs: [5], capacity: 1000 }
@0000000031 Finished All Events
Result 5

您可以在纸上手动进行此过程,您会发现我们不需要维护一个深的调用栈,这确实是一种懒加载的方式!

代码在哪里? wip

欢迎 PR!

未来计划

目前,这个项目只是处于基本形态,欢迎提出想法。

  • 定义 API
  • 添加更多示例
  • 添加 0 个外部依赖

许可证

MIT/Apache-2.0

行为准则

别在 Reddit 上给我踩分了!

常见问题解答

  • 这是不是任何 OTP 中的 actor 的另一个名字?
    • 我从未听说过它,我从未使用过 actor,我认为这是编写复杂动态图流程的明显方式,因为在我的前半生中我写 Verilog 并使用 VCS/Modelsim,我知道 DSE 是强大的!
    • 请他们为 actor 提供形式化模型并证明它是图灵完备的。
  • 为什么这被称为框架?它试图解决什么问题?
    • 为了让人们摆脱 ECS/Redux,请这些开发者证明他们的设计模式是图灵完备的。
    • 它可能是一个使用宏实现的 Q 语言,但对我来说太复杂了。

无运行时依赖