我一直在编写自己的Javascript编辑器,功能类似于Google Docs(允许多人同时处理它)。有一点我不明白:
让我们假设您已经将用户A和用户B直接相互连接,网络延迟为10毫秒。我假设编辑器使用差异系统(据我理解文档所做),其中编辑表示为"插入'文本'在索引3,"并且差异被加上时间戳并被迫按时间顺序应用于所有客户。
让我们从包含文字的文件开始:" xyz123"
用户A类型" abc"在文档的开头,在时间戳001ms,而用户B键入"你好"介于" xyz"和" 123"在时间戳005ms。
两个用户都希望结果是:" abcxyzhello123,"但是,考虑到网络延迟:
当然," abchello xyz123"与" abc xyz 你好 123"
不一样除了字面上为每个角色分配自己的唯一ID之外,我无法想象Google将如何有效地解决这个问题。
我想到的一些可能性:
我通过http://www.waveprotocol.org/whitepapers/operational-transform阅读,但很想听到解决此问题的所有方法。
答案 0 :(得分:25)
实现并发更改副本有不同的可能性,具体取决于场景的拓扑结构和不同的权衡。
最常见的情况是所有客户都必须与之通信的中央服务器。
服务器可以跟踪每个参与者的文档的外观。然后,A和B都会将更改发送到服务器。然后,服务器将更改应用于相应的跟踪文档。然后它将执行三向合并并将更改应用于主文档。然后,它将主文档和跟踪文档之间的差异发送到相应的客户端。这称为differential synchronization。
另一种方法称为操作(al)转换,类似于传统版本控制系统中的rebase。它不需要中央服务器,但是如果你有超过2个参与者,那么让它变得更容易(参见OT FAQ)。要点是您在一次编辑中转换更改,以便编辑假定已经发生了另一次编辑的更改。例如。 A会根据结果insert(3, hello)
对其编辑insert(0, abc)
转换B的修改insert(6, hello)
。
变基和OT之间的区别在于,如果您在不同的顺序中应用编辑,则变基不能保证一致性(例如,如果B反向重新编译A的编辑,则可能导致文档状态不同)。另一方面,OT的承诺是允许任何顺序,如果你做了正确的转换。
最后,有一组称为CRDT,WOOT,treedoc和logoot的算法,它们试图通过特殊设计的数据类型来解决问题,这些数据类型允许操作通勤,因此它们的应用顺序无关紧要(这类似于你对每个角色的ID的想法)。这里的权衡是内存消耗和运营构建的开销。