给出一些像这样的代码
public class CustomCollectionClass : Collection<CustomData> {}
public class CustomData
{
string name;
bool finished;
string result;
}
public async Task DoWorkInParallel(CustomCollectionClass collection)
{
// collection can be retrieved from a DB, may not exist.
if (collection == null)
{
collection = new CustomCollectionClass();
foreach (var data in myData)
{
collection.Add(new CustomData()
{
name = data.Name;
});
}
}
// This part doesn't feel safe. Not sure what to do here.
var processTasks = myData.Select(o =>
this.DoWorkOnItemInCollection(collection.Single(d => d.name = o.Name))).ToArray();
await Task.WhenAll(processTasks);
await SaveModifedCollection(collection);
}
public async Task DoWorkOnItemInCollection(CustomData data)
{
await DoABunchOfWorkElsewhere();
// This doesn't feel safe either. Lock here?
data.finished = true;
data.result = "Parallel";
}
正如我在一些内联评论中所指出的那样,对我来说做上述事情并不安全,但我不确定。我有一些元素集合,我希望为每个并行任务分配一个唯一元素,并让这些任务能够根据完成的工作修改集合中的单个元素。最终的结果是,我希望在个别之后保存集合,并行修改不同的元素。如果这不是一个安全的方法,那么我最好怎么做呢?
答案 0 :(得分:0)
您的上述代码应该可以正常运行。您将一个项目传递给每个工作线程。我不太确定async属性。您可能只返回一个任务,然后在您的方法中执行:
public Task DoWorkOnItemInCollection(CustomData data)
{
return Task.Run(() => {
DoABunchOfWorkElsewhere().Wait();
data.finished = true;
data.result = "Parallel";
});
}
您可能需要小心,对于大量项目,您可能会使用后台线程溢出最大线程数。在这种情况下,c#只会删除您的线程,以后可能很难调试。
我以前做过这个,如果不是将整个集合交给一些神奇的linq,而是将一个典型的消费者问题解决,可能会更容易:
class ParallelWorker<T>
{
private Action<T> Action;
private Queue<T> Queue = new Queue<T>();
private object QueueLock = new object();
private void DoWork()
{
while(true)
{
T item;
lock(this.QueueLock)
{
if(this.Queue.Count == 0) return; //exit thread
item = this.Queue.DeQueue();
}
try { this.Action(item); }
catch { /*...*/ }
}
}
public void DoParallelWork(IEnumerable<T> items, int maxDegreesOfParallelism, Action<T> action)
{
this.Action = action;
this.Queue.Clear();
this.Queue.AddRange(items);
List<Thread> threads = new List<Thread>();
for(int i = 0; i < items; i++)
{
ParameterizedThreadStart threadStart = new ParameterizedThreadStart(DoWork);
Thread thread = new Thread(threadStart);
thread.Start();
threads.Add(thread);
}
foreach(Thread thread in threads)
{
thread.Join();
}
}
}
这是免费的IDE,因此可能存在拼写错误。
答案 1 :(得分:0)
我将建议您使用Microsoft的Reactive Framework(NuGet&#34; Rx-Main&#34;)来执行此任务。
以下是代码:
'filter%5Bid%5D'
完成。就是这样。没什么。
我不得不说,当我试图让你的代码运行时,它充满了错误和问题。我怀疑您发布的代码不是您的生产代码,而是您专门针对此问题编写的示例。我建议您在发布之前尝试制作一个可运行的可编辑示例。
然而,我的建议应该适合你一点点调整。
它是多线程和线程安全的。完成后它确实干净地保存修改后的集合。