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()
.
我正在尝试使用自定义 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()
.