C++ 查询不断增长的数据集
我们有一个在应用程序处理数据集时不断增长的数据集。经过长时间的讨论,我们决定现在不需要阻塞或异步API,我们将定期查询数据存储 我们考虑了两个选项来设计用于查询存储的API:C++ 查询不断增长的数据集,c++,C++,我们有一个在应用程序处理数据集时不断增长的数据集。经过长时间的讨论,我们决定现在不需要阻塞或异步API,我们将定期查询数据存储 我们考虑了两个选项来设计用于查询存储的API: 查询方法返回数据的快照和一个标志,指示我们是否可能有更多数据。当我们完成对最后一个返回的快照的迭代后,我们将再次查询以获取其余数据的另一个快照 查询方法在数据上返回一个“活动”迭代器,当该迭代器前进时,它返回以下选项之一:数据可用,没有更多数据,可能有更多数据 我们使用C++,我们借用了.NET样式枚举器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;
};
/*==================================================================*/
//类似于familier.NET枚举器。
类IFooEnumerator
{
//true-->可以使用Current()方法访问数据元素
//false-->序列结束。调用Current()是无效的操作。
虚拟布尔移动下一步()=0;
虚拟Foo Current()常量=0;
虚拟~IFooEnumerator(){}
};
枚举类可用性
{
EndOfData,
可能有更多的数据,
};
类IDataProvider
{
//查询参数允许指定起始元素的ID。以下是预期的使用模式:
//1.调用GetFoo()而不指定起点。
//2.处理IFooEnumerator返回的所有元素,直到结束。
//3.检查可用性。
//3.1可能有MoreDataLater-->在一段时间后通过指定最后处理的元素作为起点再次调用GetFoo()
//并重复步骤(2)和(3)
//3.2 EndOfData-->数据集将不再增长,我们知道已完成处理。
虚拟std::tuple GetFoo(查询参数)=0;
};
/*=======第二个选项========*/
枚举类可用性
{
HasData,
可能有更多的数据,
EndOfData,
};
类IGrowingFooEnumerator
{
//HasData:
//我们可以通过调用current()来访问当前数据元素
//EndOfData:
//数据集已完成增长,以后不会有更多的数据元素到达
//可能有更多数据:
//数据集将增长,我们需要继续定期调用MoveNext()(最好在短时间延迟后)
//直到我们得到“HasData”或“EndOfData”结果。
虚拟可用性MoveNext()=0;
虚拟Foo Current()常量=0;
虚拟~IFooEnumerator(){}
};
类IDataProvider
{
std::unique_ptr GetFoo(查询参数)=0;
};
更新 鉴于目前的答案,我有一些澄清。争论主要集中在界面上——它在表示不断增长的数据集的查询时的表现力和直观性,这些数据集在某个时间点将停止增长。由于以下特性,在没有竞争条件的情况下(至少我们认为是这样),两个接口的实现都是可能的:
你打算怎么做?如果它使用的是先前返回的
IFooEnumerator
,那么这两个选项在功能上是等效的。否则,让调用者销毁“枚举器”,然后调用GetFoo()
以继续迭代,这意味着您将失去监视客户端对查询结果的持续兴趣的能力。可能现在您不需要这样做,但我认为在整个结果处理过程中排除跟踪状态的能力是一种糟糕的设计。这实际上取决于许多事情,整个系统是否能够正常工作(不涉及实际实现的细节):
可能有更多数据状态是什么意思-要么有,要么没有,对吗?重复轮询更多数据是一个坏主意