假设我有两个或多个处理SQLite数据库的进程 - 一个“播放器”进程和许多“编辑器”进程。
“播放器”进程读取数据库并更新视图 - 在我的情况下,根据存储在数据库中的事件,它将是混合到声卡的波形。
“编辑器”进程是该数据库的任何编辑器:它会不断更改数据库。
现在我希望播放器快速反映编辑更改。
我知道SQLite提供了在同一进程中跟踪数据库更改的钩子,但似乎没有关于如何使用多个进程执行此操作的信息。
我可以不断地轮询数据库,比较记录和触发事件,但这似乎效率很低,特别是当数据库增长到很大的时候。
我正在考虑使用日志表和触发器,但我想知道是否有更简单的方法。
答案 0 :(得分:5)
关系数据库不是您最好的首选。
为什么?
您希望所有编辑都将更改传递给您的播放器。
您的播放器 - 实际上 - 是所有这些编辑器的服务器。您的播放器需要多个开放连接。它必须听取所有这些连接的变化。它必须显示这些变化。
如果更改非常大,您可以转到混合解决方案,其中编辑器会持续进行更改和通知播放器。
无论哪种方式,编辑都必须通知他们玩家他们有变化。它比试图发现数据库变化的玩家简单得多。
更好的设计是接受来自编辑者的消息,持久化并通知玩家的服务器。此服务器既不是编辑器也不是播放器,而只是一个确保处理所有消息的代理。它接受来自编辑和玩家的连接。它管理数据库。
有两种实现方式。服务器是播放器。服务器与播放器分开。服务器的设计不会改变 - 只有协议。当服务器是播放器时,服务器直接调用播放器对象。当服务器与播放器分开时,服务器会写入播放器的套接字。
当播放器是服务器的一部分时,当从编辑器收到消息时,将直接调用播放器对象。当播放器是独立的时,小型阅读器从套接字收集消息并调用播放器对象。
播放器连接到服务器,然后等待信息流。这可以从编辑器输入,也可以是服务器在数据库中持久存储的数据的引用。
如果您的消息流量足够小,以便网络延迟不成问题,编辑器会将所有数据发送到服务器/播放器。如果消息流量太大,则编辑器会写入数据库并向服务器/播放器发送仅带有数据库FK的消息。
请澄清“如果编辑在通知时崩溃,则播放器会在你的问题中永久搞乱”。
这听起来像是播放器服务的糟糕设计。它不能“永久搞砸”,除非它没有得到各个编辑的状态。如果它从编辑器获得状态(但是试图镜像那个状态,那么)你应该考虑一种设计,其中玩家只是从编辑器获得状态而不能“永久搞砸”。
答案 1 :(得分:3)
SQLite有一个update_hook
函数可以满足您的需求。
SQLite C接口
数据更改通知回调
void *sqlite3_update_hook(
sqlite3*,
void(*)(void *,int ,char const *,char const *,sqlite3_int64),
void*
);
sqlite3_update_hook()
接口注册回调函数 由要调用的第一个参数标识的数据库连接 每当在rowid表中更新,插入或删除行时。任何 由先前调用此函数为同一数据库设置的回调 连接被覆盖。
不幸的是,Python sqlite模块没有公开它......
这是一个有点hacky的解决方法,深入研究C api(来自Python代码)以利用它: https://stackoverflow.com/a/16920926
答案 2 :(得分:2)
只需在两个进程之间打开一个套接字,让编辑器告诉所有玩家有关更新的信息。
答案 3 :(得分:2)
我认为在这种情况下,我会创建一个管理数据库读/写的过程。
每个想要对数据库进行一些修改的编辑都会通过IPC或网络或其他任何方法调用此过程。
然后,此过程可以通知玩家数据库中的更改。当玩家想要检索某些数据时,它应该向管理数据库的进程请求它想要的数据。 (或者db进程告诉它需要什么,当它通知更改时,所以不需要来自播放器的请求)
这样做的好处是只有一个进程访问SQLite数据库,因此数据库上没有锁定或并发问题。
答案 4 :(得分:1)
编辑:我在同一台计算机上处理进程。
在我看来,有两种方式:
轮询(如您所述),但将其保留为单个值(就像保留其他表的LastUpdateTime的表一样)
使用目标平台上可用的进程间通信。这可能是Windows中的事件(例如,在C#中(我不知道在Python中)ManualResetEvent,AutoResetEvent,或者如果你想在每个进程中牺牲一个服务器线程,则可以是Mutex),或者在Linux中是Signals。
答案 5 :(得分:1)
如果它在同一台机器上,最简单的方法是使用命名管道,“播放器”使用阻塞read()和“编辑器”在修改数据库时将令牌放入管道。
答案 6 :(得分:1)
有多少编辑器进程(为什么要处理?),以及您希望更新的频率如何?这听起来不是一个好的设计,特别是考虑到sqlite对于多次并发访问数据库感到非常高兴
。如果多个进程有意义和您需要持久性,那么让编辑者通过套接字,管道,共享内存等通知您的播放器可能更为明智。然后让玩家(也就是服务器进程)做持久化。