我们有一个数据集,在应用程序处理数据集时会增长。经过长时间的讨论,我们决定此时不需要阻塞或异步API,我们将定期查询数据存储。
我们考虑了两种设计用于查询存储的API的选项:
我们正在使用C ++,并且我们借用了.NET样式枚举器API,原因超出了这个问题的范围。这里有一些代码来演示这两个选项。您更喜欢哪个选项?
/* ======== FIRST OPTION ============== */
// similar to the familier .NET enumerator.
class IFooEnumerator
{
// true --> A data element may be accessed using the Current() method
// false --> End of sequence. Calling Current() is an invalid operation.
virtual bool MoveNext() = 0;
virtual Foo Current() const = 0;
virtual ~IFooEnumerator() {}
};
enum class Availability
{
EndOfData,
MightHaveMoreData,
};
class IDataProvider
{
// Query params allow specifying the ID of the starting element. Here is the intended usage pattern:
// 1. Call GetFoo() without specifying a starting point.
// 2. Process all elements returned by IFooEnumerator until it ends.
// 3. Check the availability.
// 3.1 MightHaveMoreDataLater --> Invoke GetFoo() again after some time by specifying the last processed element as the starting point
// and repeat steps (2) and (3)
// 3.2 EndOfData --> The data set will not grow any more and we know that we have finished processing.
virtual std::tuple<std::unique_ptr<IFooEnumerator>, Availability> GetFoo(query-params) = 0;
};
/* ====== SECOND OPTION ====== */
enum class Availability
{
HasData,
MightHaveMoreData,
EndOfData,
};
class IGrowingFooEnumerator
{
// HasData:
// We might access the current data element by invoking Current()
// EndOfData:
// The data set has finished growing and no more data elements will arrive later
// MightHaveMoreData:
// The data set will grow and we need to continue calling MoveNext() periodically (preferably after a short delay)
// until we get a "HasData" or "EndOfData" result.
virtual Availability MoveNext() = 0;
virtual Foo Current() const = 0;
virtual ~IFooEnumerator() {}
};
class IDataProvider
{
std::unique_ptr<IGrowingFooEnumerator> GetFoo(query-params) = 0;
};
更新
鉴于目前的答案,我有一些澄清。争论主要在于界面 - 它在表达查询中的表现力和直觉性,这些数据集在某个时间点将停止增长。由于以下属性,两个接口的实现都可以在没有竞争条件的情况下(至少我们相信):
答案 0 :(得分:0)
&#34;一段时间后再次调用GetFoo(),指定最后处理的元素为起点&#34;
你打算怎么做?如果它使用之前返回的IFooEnumerator
,那么在功能上这两个选项是等效的。否则,让调用者破坏&#34;枚举器&#34;然而,不久之后,请致电GetFoo()
继续迭代意味着您失去了监控客户对查询结果持续兴趣的能力。可能就是现在你没有必要这样做,但我认为在整个结果处理过程中排除跟踪状态的能力是不好的设计。
答案 1 :(得分:0)
这真的取决于很多事情,整个系统是否会全部工作(没有详细介绍你的实际实施):
关于您的实施,在选项2中,我不确定您对MightHaveMoreData
州的意思 - 它有没有,或者它没有,对吗?在这种情况下,重复轮询获取更多数据是一个糟糕的设计 - 假设您永远无法100%确定没有新数据&#34;提取从获取最后一个数据到处理和采取行动所花费的时间(显示,用于购买股票市场上的股票,停止火车或您处理新数据后想要做的任何事情) 。
答案 2 :(得分:0)
读写锁可能有所帮助。许多读者可以同时访问数据集,只有一个编写者。 这个想法很简单: - 当您需要只读访问权限时,阅读器使用&#34; read-block&#34 ;,可以与其他读取共享,与写入者独占; - 当您需要写入权限时,writer使用写锁定,这对读者和作者都是独有的;