我不确定这个标题是否很好地表达了对不起。
我基本上有一堆列出通信目标的元素。我将它们放在字典中虽然我愿意将它们移动到不同的数据结构中。我的问题是我有一个树状结构,其中一个键是一个分支,每个分支有很多叶子。分支和叶子都有以字符串形式存储的名称(不能是数字)。
private Dictionary < string, string[]> targets;
对于字典中的每个元素,我必须发送一个通信,当目标应答时,我会转到下一个目标并重新开始。所以在搜索之后我面临着这些困境:
我在C#上相当新,所以答案可能很明显,但我发现很难找到符合我需求的数据结构。什么是最简单的解决方案?有人可以提出什么建议吗?
谢谢。
修改
我认为我的帖子让很多人感到困惑,而且他们有点卡在指针和线程上。通过线程我并不意味着它们是并行的,只是因为我不能使用 foreach 或循环作为下一个迭代的下一个线程由传入通信触发。此机制目前无法更改,只需迭代即可。通过指针,我没有提到C中经常使用的内存指针,我只想指出你在列表中的位置。对不起,我是一名Java程序员,所以我可能会使用令人困惑的条款。
我注意到 Enumerator 经常被继承,并且可以与Dictionary和Linked List等结构一起使用。我找到了关于这个子结构被封装的例子,并以 foreach 循环为例。
是否可以以某种方式使用 GetEnumerator (),即使通过不同的线程访问,枚举器也会记住当前位置?
我要自己测试这些,但是如果有经验的人提供的任何意见总是受到赞赏!
答案 0 :(得分:3)
您可以使用Parallel.ForEach方法(来自.NET 4)并行枚举此内容。它已作为Rx Framework的一部分向后移植,以便在.NET 3.5sp1中使用。
注意 - 这实际上并不是每个项目使用一个线程,而是根据您正在执行的系统的硬件线程数(通常更好......)使用线程池对工作进行分区。 。在.NET 4中,它利用了ThreadPool的新爬山和工作窃取算法,因此非常有效。
答案 1 :(得分:3)
我认为你需要重新设计一下你的架构,字典本身可能不是你需要用于有序迭代的数据结构。
我会考虑将您的树移动到链接列表中。
当您启动通信时,我建议让您的线程回调一个委托来更新您的列表数据,或者另一个共享数据结构,以跟踪您在通信过程中的位置。
static LinkedList<LeafItem> TreeList = new LinkedList<LeafItem>( );
foreach (LeafItem li in TreeList) {
Thread newThread = new Thread(
new ParameterizedThreadStart(Work.DoWork));
newThread.Start(li);
}
答案 2 :(得分:0)
编辑:来自您的评论:
我的算法更像是:得到 第一个目标发送消息给 第一个目标线程DIES - 抓住一个 港口接待事件检查是否是 正确的目标做一些行动 - 去 下一个目标开始循环。
如果要异步处理项目但并行处理不,则应该能够通过将字典的键复制到Queue<string>
并将两者都传递给处理的回调来实现这一点。你的异步响应。
您的完成处理程序pseduo-code可能如下所示:
// first extract your dictionary, key, and queue from whatever state
// object you're using to pass data back to the completion event
if (dictionary.Contains(key)) {
// process the response
}
if (queue.Count > 0) {
string key = queue.Dequeue();
string[] messages = dictionary[key];
// send the messages, along with your state data and this callback
}
答案 3 :(得分:0)
这是一个轻微的远射,我怀疑我在这里弄乱了它:/
基本上我们的想法是为您的字典创建自定义IEnumerator
。这个想法是它包含一个静态变量,用于保持枚举的“位置”,以便继续。
以下是一些可用于暂停和重新启动的框架代码。
public class MyDictEnumerator<T> : IEnumerator<T>
{
private List<T> Dict;
private static int curLocation = -1;
public MyDictEnumerator(List<T> dictionary)
{
Dict = dictionary;
}
public T Current
{
get { return Dict[curLocation]; }
}
public void Dispose()
{ }
object System.Collections.IEnumerator.Current
{
get { return Dict[curLocation]; }
}
public bool MoveNext()
{
curLocation++;
if (curLocation >= Dict.Count)
return false;
return true;
}
public void Reset()
{
curLocation = -1;
}
}
然后使用:
MyDictEnumerator<KeyValuePair<string, int>> enumer = new MyDictEnumerator<KeyValuePair<string, int>>(test.ToList());
while (enumer.MoveNext())
{
Console.WriteLine(enumer.Current.Value);
}
我承认这不是最干净的方式。但是如果你打破了枚举器,并在另一个线程上创建一个新的,那么它将继续在同一点(我认为:/)
我希望这会有所帮助。