用队列处理MySQL的线程
本文关键字:线程 MySQL 处理 队列 | 更新日期: 2023-09-27 18:07:07
现在我在一个类中有很多INSERT/UPDATE/DELETE/SELECT方法。它们都共享一个Connection、一个DataReader和一个Command。但是当从DB下载数据或上传数据时,它们会冻结UI。它在本地网络上是ok的,但由于它使用外部服务器的DB,它有时会冻结。所以我想让所有MySQL类在另一个线程上。
我需要像DoThisInAnotherThread(mysql.UpdateTable)。但是必须有某种队列,因为所有方法都使用相同的Connection和相同的DataReader。让每一种方法都建立自己的连接看起来并不是最好的解决方案。
我在寻找最好和最简单的解决方案。类似于任务队列,它将由另一个线程检查并执行,而它不会为空。
我尝试了BackgroundWorker,但是没有队列。我听说一些关于启动自己的线程,但我没有看到一种方法,如何使它运行和等待任务。
谢谢。
您可以使用工作队列,它将在单个线程上执行所有工作。在那里,您可以保持单个sql连接,并且同步将很简单,因为所有命令都是顺序执行的。
看下面的示例WorkQueue实现(注意它缺少异常处理):
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
class App
{
static void Main()
{
var q = new WorkQueue();
q.Execute(() => Console.WriteLine("A"));
q.Execute(() => Console.WriteLine("B"));
Task<int> t = q.Execute(() => 33);
Console.WriteLine(t.Result);
q.Dispose();
}
}
public class WorkQueue : IDisposable
{
private readonly Thread thread;
private readonly BlockingCollection<Action> queue;
public WorkQueue()
{
this.queue = new BlockingCollection<Action>();
this.thread = new Thread(DoWork);
this.thread.Start();
}
public Task<T> Execute<T>(Func<T> f)
{
if (this.queue.IsCompleted) return null;
var source = new TaskCompletionSource<T>();
Execute(() => source.SetResult(f()));
return source.Task;
}
public void Execute(Action f)
{
if (this.queue.IsCompleted) return;
this.queue.Add(f);
}
public void Dispose()
{
this.queue.CompleteAdding();
this.thread.Join();
}
private void DoWork()
{
foreach (var action in this.queue.GetConsumingEnumerable())
{
action();
}
}
}
您可能需要:
- 实现一个表示sql查询结果的类,例如
SQLResult
,它将进一步专门化到每种查询类型。 - special
Task<SQLResult>
(documentation):该类包含查询任务完成状态所需的API。 - 使用
TaskScheduler
(文档),它携带您正在寻找的队列语义。