全部,我有一个名为TaskSpin
的通用方法,在此方法中,我使用ascociated Task
continutation
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
// Finish the processing update UI etc.
}
...
}
现在的问题是我想使用TaskSpin
运行多个方法,但我需要限制方法一次一个地运行。所以在某些DataGridView
中的foreach行我想做类似
foreach (DataGridViewRow row in this.DataGridViewUrg.Rows)
TaskSpin(Run(DrgDataRowInfo(row.Index)));
但是,在上面,TaskSpin
方法将立即退出,导致TaskSpin
在另一个线程上剥离下一个方法。这并不好,因为Run
方法写入一组公共文件。排队这些工作的最佳方法是什么?
感谢您的时间。
答案 0 :(得分:1)
您可以实现自己的任务队列,并在每个任务完成后继续处理队列,直到它为空。例如
using TaskPair = KeyValuePair<Func, object[]>;
...
private Queue<TaskPair> taskQueue;
...
// generate the queue of tasks
this.taskQueue = new Queue<TaskPair>(this.DataGridViewUrg.Rows);
foreach (DataGridViewRow row in this.DataGridViewUrg.Rows)
{
var task = new TaskPair(Run(DrgDataRowInfo(row.Index)), /* params */);
this.taskQueue.Enqueue(task);
}
// initiate queue processing
ProcessNextTask();
....
private void ProcessNextTask()
{
try
{
var item = this.taskQueue.Dequeue();
TaskSpin(item.Key, item.Value);
}
catch(InvalidOperationException)
{
// queue is empty
}
}
....
// Execute task and process next in queue (if applicable)
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
// Finish the processing update UI etc.
ProcessNextTask();
}
...
}
答案 1 :(得分:1)
您可以使用延续链实现任务的“队列”。这很容易阅读和理解,并将按预期工作。此外,“排队”逻辑现在包含在TaskSpin中。
private Task lastTask;
public void TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
if(lastTask == null)
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
else
asyncTask = lastTask.ContinueWith(t =>
asyncMethod(uiScheduler, methodParameters));
lastTask = asyncTask;
asyncTask.ContinueWith(task =>
{
// Finish the processing update UI etc.
}
...
}
这将确保每个新任务仅在最后一个任务完成后运行。
编辑:如果您希望将UI任务包含在顺序队列中,只需进行一项简单的更改:
private Task lastTask;
public void TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
if(lastTask == null)
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
else
asyncTask = lastTask.ContinueWith(t =>
asyncMethod(uiScheduler, methodParameters));
lastTask = asyncTask.ContinueWith(task =>
{
// Finish the processing update UI etc.
}
...
}
答案 2 :(得分:0)
您应该考虑通过在继续之前锁定Run所需的对象来实现同步。你会喜欢以下内容:
// locking object for write synchronization
object syncObj;
...
public TaskSpin(Func asyncMethod, object[] methodParameters)
{
...
asyncTask = Task.Factory.StartNew<bool>(() =>
asyncMethod(uiScheduler, methodParameters));
asyncTask.ContinueWith(task =>
{
lock(syncObj)
{
// Finish the processing update UI etc.
}
}
...
}
public void Run()
{
lock(syncObj)
{
// write results to common file
}
}
虽然,我很确定这不会保证任务按顺序完成。这听起来对你来说可能很重要,所以我的建议可能不是你想要的。
答案 3 :(得分:0)
如果你的目标是序列化UI的更新,那么无论如何都必须这样做,因为UI只能从GUI线程更新。幸运的是,已经内置了执行此操作的机制。
我注意到你正在使用winforms。鉴于此,我建议使用SafeInvoke之类的机制。这将排队代码以便在GUI线程上执行。