虽然我意识到那里有很多这些,但我找不到适用于我的情况的东西。所以我认为我冒了重复的风险来得到我的问题的答案......
背景:
我有一个主对象(ActionsMaster),它包含一个子对象列表作为属性并处理高级方法。我的处理表格"将要处理代码以将此列表中的每个操作应用于环境,但由于应用操作的调用可以是多线程/一次支持多个调用,我认为我是高效的一次产生大约5或10个线程(想想这里成千上万的动作......我希望这个快速)。
所以为了支持这一点,我已经为我的子对象类型添加了一个Status属性,说它是否被移交给一个线程进行操作,或者它是否是免费的使用以及向ActionsMaster添加一个对象以用于锁定目的。
到目前为止的代码:
以下是我用来确定某个操作是否可用的代码,这就是我的问题所在:我可以在锁定区块内返回该对象,还是我必须考虑它是否已经过了如果我回到那里,永远不会到达锁定区的尽头?我需要在运行LINQ语句之前锁定,否则2个线程可能会得到相同的结果......这里是我的拥有:
internal ActionFileAction GetNextFreeAction()
{
lock (_IsLocked)
{
ActionFileAction action = this.Actions.DefaultIfEmpty(null).FirstOrDefault(a => a.Status == null || a.Status == Action_Status.Free);
if (action != null)
action.Status = Action_Status.Queued;
return action;
}
}
我会在后台工作者中调用它,如下所示:
void bkg_Automatic_DoWork(object sender, DoWorkEventArgs e)
{
//check for user cancel...
if (this.CancelJobs || this.IsAbort)
{
e.Cancel = true;
}
else
{
if (!this.IsFinished)
{
ActionFileAction action = this.TheFile.GetNextFreeAction();
if (action == null)
{
this.IsFinished = true;
}
else
{
//PROCESS THE ACTION HERE...
}
}
}
e.Result = true;
}
只是为了彻底,这是我的RunWorkerCompleted代码:
void bkg_Automatic_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
GenericLogEntry ent = new GenericLogEntry();
ent = new GenericLogEntry();
ent.Area = "SYSTEM";
ent.Action = "USER ABORT";
ent.Description = this.CancelJobs == true ? "CLOSED FORM" : "PUSHED ABORT BUTTON";
ent.Stamp = DateTime.Now;
ent.Status = LogEntryStatus.Fail;
UpdateLogView(ent);
}
else
{
if (this.IsFinished)
{
//add all processed actions to the deployment results, if not already done.
}
else
{
//spawn new thread from this one's END...
BackgroundWorker bkg1 = new BackgroundWorker();
bkg1.DoWork += new DoWorkEventHandler(bkg_Automatic_DoWork);
bkg1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkg_Automatic_RunWorkerCompleted);
bkg1.WorkerSupportsCancellation = true;
bkg1.RunWorkerAsync();
}
}
}
这是我正在努力完成的正确方法吗?
答案 0 :(得分:1)
Task Parallel Library附带.Net框架的v4,并将为您处理所有这些。学习如何使用它有一点点开销,但最终我认为你喜欢学习一个久经考验的标准库,而不是花时间自己制作它。
基本上你可以把它的任务交给执行,它会处理它们的排队并在池中的线程上运行它们。
Here is an MSDN tutorial关于使用TPL,虽然其中的代码不是很清楚。 这里的another article可能更清楚。
答案 1 :(得分:1)
将工作卸载到多个线程并不总是答案。 在尝试将工作转移到后台线程时,您应该始终考虑您的计算机具有多少核心。在具有2个内核的计算机上启动5-10个线程将导致大量上下文切换,这可能最终降低代码性能。
现在,解决方案。如果您的目标是.NET 4.0或更高版本,我建议您使用带有TPL组合的ConcurrentQueue。你的代码看起来像这样:
private ConcurrentQueue<ActionFileAction> _actionFileQueue = new ConcurrentQueue<ActionFileAction>();
internal ActionFileAction GetNextFreeAction(CancellationToken cancellationToken = default(CancellationToken))
{
// Checks if a cancellation was requested
cancellationToken.ThrowIfCancellationRequested();
ActionFileAction actionFileToHandle;
_actionFileQueue.TryDequeue(out actionFileToHandle);
//may return null if couldn't dequeue
return actionFileToHandle;
}
//C# Methods should be CamelCase without underscores
void HandleAllActionFiles()
{
try
{
var cancellationToken = new CancellationTokenSource().Token;
Parallel.Invoke(
new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = cancellationToken
}, () => GetNextFreeAction());
}
catch (OperationCanceledException e)
{
// Do stuff with cancellation
}
}
当然,您仍然需要处理重试并不断收听队列以查看某个项目是否在等待,但这可以让您开始:)