项目数未知时定义下一个起点
Define Next Start Point When Number of Items Unknown
我有一个需要查询的 Web 服务,它需要一个支持其数据分页的值。由于我需要获取的数据量以及该服务的实现方式,我打算执行一系列并发的 http 网络请求来积累这些数据。
假设我有线程数和页面大小,我如何分配每个线程来选择不与其他线程重叠的起点?自从我进行并行编程以来已经有很长一段时间了,而且我有点挣扎。我知道我可以用 start = N/numThreads * threadNum
之类的东西找到我的起点,但我不知道 N。现在我只是启动 X 个线程和每个循环,直到它们没有更多数据。问题是它们往往会重叠,我最终会得到重复的数据。我需要独特的数据而不是浪费请求。
现在我的代码看起来像这样。这是许多尝试之一,我明白为什么这是错误的,但最好展示一些东西。目标是从网络服务并行收集数据页面:
int limit = pageSize;
data = new List<RequestStuff>();
List<Task> tasks = new List<Task>();
for (int i = 0; i < numThreads; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
try
{
List<RequestStuff> someData;
do
{
int start;
lock(myLock)
{
start = data.Count;
}
someKeys = GetDataFromService(start, limit);
lock (myLock)
{
if (someData != null && someData.Count > 0)
{
data.AddRange(someData);
}
}
} while (hasData);
}
catch (AggregateException ex)
{
//Exception things
}
}));
}
Task.WaitAll(tasks.ToArray());
在没有竞争条件的情况下解决这个问题有什么灵感吗?如果这很重要,我需要坚持使用 .NET 4。
您是否试图通过发出多个并发请求来强制远程服务并行?分页通常用于将返回的数据量限制为仅需要的数据量,但是如果您需要所有数据,那么尝试先分页然后再重建它似乎是一个糟糕的设计。您的代码变得不必要地复杂,难以维护,您可能只是将瓶颈从您控制的代码转移到其他地方,现在您已经引入了数据完整性问题(如果所有这些线程访问不同版本的数据会发生什么正在尝试查询?)。通过增加调用的复杂性和数量,您也增加了发生问题的可能性(例如,其中一个连接断开)。
您能否说明您正试图解决的问题,这样或许我们可以帮助设计更好的解决方案?
除非您知道实际限制,否则我不确定是否有办法在不浪费一些请求的情况下执行此操作。下面的代码可能有助于消除重复数据,因为您只需在每个索引上查询一次:
private int _index = -1; // -1 so first request starts at 0
private bool _shouldContinue = true;
public IEnumerable<RequestStuff> GetAllData()
{
var tasks = new List<Task<RequestStuff>>();
while (_shouldContinue)
{
tasks.Add(new Task<RequestStuff>(() => GetDataFromService(GetNextIndex())));
}
Task.WaitAll(tasks.ToArray());
return tasks.Select(t => t.Result).ToList();
}
private RequestStuff GetDataFromService(int id)
{
// Get the data
// If there's no data returned set _shouldContinue to false
// return the RequestStuff;
}
private int GetNextIndex()
{
return Interlocked.Increment(ref _index);
}
还可以通过添加取消令牌来取消您知道是浪费的任何索引来改进它,即,如果索引 4 returns 什么都没有,您可以取消对 4 以上索引的所有查询,这些查询仍然处于活动状态。
或者,如果您可以对最大索引做出合理的猜测,您或许能够实施一种算法来在检索任何数据之前查明确切的限制。不过,如果您的猜测相当准确,这可能只会更有效率。
我有一个需要查询的 Web 服务,它需要一个支持其数据分页的值。由于我需要获取的数据量以及该服务的实现方式,我打算执行一系列并发的 http 网络请求来积累这些数据。
假设我有线程数和页面大小,我如何分配每个线程来选择不与其他线程重叠的起点?自从我进行并行编程以来已经有很长一段时间了,而且我有点挣扎。我知道我可以用 start = N/numThreads * threadNum
之类的东西找到我的起点,但我不知道 N。现在我只是启动 X 个线程和每个循环,直到它们没有更多数据。问题是它们往往会重叠,我最终会得到重复的数据。我需要独特的数据而不是浪费请求。
现在我的代码看起来像这样。这是许多尝试之一,我明白为什么这是错误的,但最好展示一些东西。目标是从网络服务并行收集数据页面:
int limit = pageSize;
data = new List<RequestStuff>();
List<Task> tasks = new List<Task>();
for (int i = 0; i < numThreads; i++)
{
tasks.Add(Task.Factory.StartNew(() =>
{
try
{
List<RequestStuff> someData;
do
{
int start;
lock(myLock)
{
start = data.Count;
}
someKeys = GetDataFromService(start, limit);
lock (myLock)
{
if (someData != null && someData.Count > 0)
{
data.AddRange(someData);
}
}
} while (hasData);
}
catch (AggregateException ex)
{
//Exception things
}
}));
}
Task.WaitAll(tasks.ToArray());
在没有竞争条件的情况下解决这个问题有什么灵感吗?如果这很重要,我需要坚持使用 .NET 4。
您是否试图通过发出多个并发请求来强制远程服务并行?分页通常用于将返回的数据量限制为仅需要的数据量,但是如果您需要所有数据,那么尝试先分页然后再重建它似乎是一个糟糕的设计。您的代码变得不必要地复杂,难以维护,您可能只是将瓶颈从您控制的代码转移到其他地方,现在您已经引入了数据完整性问题(如果所有这些线程访问不同版本的数据会发生什么正在尝试查询?)。通过增加调用的复杂性和数量,您也增加了发生问题的可能性(例如,其中一个连接断开)。
您能否说明您正试图解决的问题,这样或许我们可以帮助设计更好的解决方案?
除非您知道实际限制,否则我不确定是否有办法在不浪费一些请求的情况下执行此操作。下面的代码可能有助于消除重复数据,因为您只需在每个索引上查询一次:
private int _index = -1; // -1 so first request starts at 0
private bool _shouldContinue = true;
public IEnumerable<RequestStuff> GetAllData()
{
var tasks = new List<Task<RequestStuff>>();
while (_shouldContinue)
{
tasks.Add(new Task<RequestStuff>(() => GetDataFromService(GetNextIndex())));
}
Task.WaitAll(tasks.ToArray());
return tasks.Select(t => t.Result).ToList();
}
private RequestStuff GetDataFromService(int id)
{
// Get the data
// If there's no data returned set _shouldContinue to false
// return the RequestStuff;
}
private int GetNextIndex()
{
return Interlocked.Increment(ref _index);
}
还可以通过添加取消令牌来取消您知道是浪费的任何索引来改进它,即,如果索引 4 returns 什么都没有,您可以取消对 4 以上索引的所有查询,这些查询仍然处于活动状态。
或者,如果您可以对最大索引做出合理的猜测,您或许能够实施一种算法来在检索任何数据之前查明确切的限制。不过,如果您的猜测相当准确,这可能只会更有效率。