1

现在我在一个类中有很多 INSERT/UPDATE/DELETE/SELECT 方法。它们都共享一个 Connection、一个 DataReader 和一个 Command。但是在从数据库下载数据或上传数据时,它们会冻结 UI。在本地网络上没问题,但由于它使用外部服务器作为数据库,它有时会冻结。所以我想在另一个线程上创建所有 MySQL 类。

我需要类似 DoThisInAnotherThread(mysql.UpdateTable) 的东西。但是必须有某种队列,因为所有方法都使用相同的 Connection 和相同的 DataReader。并且让每一种方法来建立自己的连接看起来都不是最好的解决方案。

我正在寻找最好和最简单的解决方案。任务队列之类的东西,将由另一个线程检查并执行,但它不会为空。

我试过BackgroundWorker,但没有队列。我听说了一些关于启动自己的线程的事情,但我没有看到方法,如何让它运行并等待任务。

谢谢你。

4

2 回答 2

1

您可能需要:

  • 实现一个表示 sql 查询结果的类,比如SQLResult,它将进一步专门用于每种类型的查询。
  • 专业化Task<SQLResult>文档):该类提供查询任务完成状态所需的 API。
  • 使用TaskScheduler文档),它携带您正在寻找的排队语义。
于 2013-04-01T20:55:13.043 回答
1

您可以使用工作队列,它将在单个线程上执行所有工作。在那里您可以保持单个 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();
    }
  }
}
于 2013-04-01T21:38:02.347 回答