队列多线程方法执行(Queue Multithreaded Methods for Executio

2019-09-20 15:06发布

好,我有一个名为泛型方法TaskSpin ,在这个方法我推出一个Task与ascociated 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 ,但我需要限制的方法来运行一个-AT-A-时间。 所以的foreach行中一些DataGridView我想要做这样的事情

foreach (DataGridViewRow row in this.DataGridViewUrg.Rows)
    TaskSpin(Run(DrgDataRowInfo(row.Index)));

然而,在上述TaskSpin方法将立即退出引起TaskSpin分拆下一个方法上的另一个线程。 这是没有好为Run方法写一组共同文件。 什么是排队这些职位的最佳方法是什么?

Answer 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();           
    }  
    ...                 
}


Answer 2:

您可以实现使用延续链任务的“队列”。 这是很容易阅读和理解,并会正常运行。 此外,“排队”的逻辑现在包含您的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.
    }
    ...
}


Answer 3:

你或许应该想想通过继续运行之前需要锁定的对象实现同步。 你会像下面这样:

// 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
    }
}

虽然,我敢肯定,这将无法保证任务完成才能。 这听起来像它可能对你很重要,所以可能我的建议是不正是你想要的。



Answer 4:

如果你的目标是连载更新到用户界面,这有因为UI只能从GUI线程更新反正发生。 幸运的是,机制要做到这一点已经内置的。

我注意到,您正在使用的WinForms。 鉴于此,我建议使用一种机制,如SafeInvoke 。 这将排队代码GUI线程上执行。



文章来源: Queue Multithreaded Methods for Execution