TPL 生产者消费者模式 - 可能不会在已经启动的任务上调用启动

TPL Producer consumer pattern - Start may not be called on a task that was already started

我正在尝试使用自定义 sql clr 代码在 sql 服务器内部实现并行处理,如下面的示例 link。

http://www.sqlnotes.info/2015/12/03/run-t-sql-in-parallel/

上述示例的问题 link 是它使用线程和锁,这会消耗大量时间。因此,在许多情况下,并行处理的收益可以忽略不计。因此,为了解决这个问题,我正在尝试创建一个类似的实用程序,它使用 TPL 使用生产者-消费者模式。

生产者 - 是 sql 调用代码执行 sql 命令的过程。 消费者 - 该实用程序应该并行处理这些查询。

我将通过使用 begin transaction、commit 和 sp_getapplock 发送要分批处理的查询。消费者应该从 begin 开始,并在提交事务时继续寻找要处理和结束的新任务。为此,我尝试使用以下代码:

List<Task> PendingTaskList = new List<Task>();

    void StartWorker()
    {
        (Task.Factory.StartNew(() =>
        {
            while (!IsClosed)
            {
                Parallel.ForEach(PendingTaskList, new ParallelOptions { MaxDegreeOfParallelism = 10 }, task =>
                {
                    if (task.Status == TaskStatus.Created)
                    {
                        task.Start();
                    }
                });
                while ((!IsClosed) && (PendingTaskList.Count == 0)) Task.Delay(1);
            }
        }, TaskCreationOptions.LongRunning)).Start();
    }


    void Enqueue(string commandText, SqlParameter[] paramList, string queryName, string attributeSysCode)
    {
        //TODO: Localize variables in here ...
        //TODO: Do parameter checking on the T-SQL command text paased here ...
        //TODO: Consider caching pre-compiled versions of popular T-SQL parameters by hashvalue of param string here as key ...

        SqlCommand cmd = new SqlCommand();
        cmd.CommandText = commandText;
        cmd.CommandTimeout = 0;
        cmd.CommandType = CommandType.Text;

        AsyncTaskItem item = new AsyncTaskItem() { Command = cmd, sqlParamList = paramList, QueryName = queryName, AttributeSysCode = attributeSysCode };
        var task = new Task(() => RunOne(item));
        PendingTaskList.Add(task.ContinueWith(t =>
            {
                PendingTaskList.Remove(t);
                CompletedTaskList.Add(t);
            }));

    }

以上代码抛出错误"Start may not be called on a task that was already started.'"

我该如何解决这个问题?

删除对 Start() 的调用。由于 StartNew() 启动了它创建的任务,因此不需要 Start().