Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 如何启动SQL查询线程,然后在获得结果之前执行其他工作?_Mysql_Multithreading_Delphi_Scheduling - Fatal编程技术网

Mysql 如何启动SQL查询线程,然后在获得结果之前执行其他工作?

Mysql 如何启动SQL查询线程,然后在获得结果之前执行其他工作?,mysql,multithreading,delphi,scheduling,Mysql,Multithreading,Delphi,Scheduling,我有一个做有限形式多线程的程序。它是用Delphi编写的,使用libmysql.dll(C API)访问MySQL服务器。程序必须处理一长串记录,每条记录大约需要0.1秒。把它想象成一个大循环。所有的数据库访问都是由工作线程完成的,工作线程要么预取下一条记录,要么写入结果,因此主线程不必等待 在这个循环的顶部,我们首先等待预回迁线程,获取结果,然后让预回迁线程执行下一条记录的查询。其思想是预取线程将立即发送查询,并在主线程完成循环时等待结果 它通常是这样工作的。但是请注意,没有什么可以确保预取线

我有一个做有限形式多线程的程序。它是用Delphi编写的,使用libmysql.dll(C API)访问MySQL服务器。程序必须处理一长串记录,每条记录大约需要0.1秒。把它想象成一个大循环。所有的数据库访问都是由工作线程完成的,工作线程要么预取下一条记录,要么写入结果,因此主线程不必等待

在这个循环的顶部,我们首先等待预回迁线程,获取结果,然后让预回迁线程执行下一条记录的查询。其思想是预取线程将立即发送查询,并在主线程完成循环时等待结果

它通常是这样工作的。但是请注意,没有什么可以确保预取线程立即运行。我发现,通常直到主线程循环并开始等待预回迁时,查询才被发送

我通过在启动预回迁线程后立即调用sleep(0)解决了这个问题。这样,主线程将放弃剩余的时间片,希望预回迁线程现在可以运行,并发送查询。然后该线程将在等待时休眠,从而允许主线程再次运行。
当然,操作系统中运行的线程还有很多,但这确实在某种程度上起到了作用

我真正想做的是让主线程发送查询,然后让工作线程等待结果。使用libmysql.dll调用

result := mysql_query(p.SqlCon,pChar(p.query));
在工作线程中。相反,我希望主线程调用

mysql_threadedquery(p.SqlCon,pChar(p.query),thread);
一旦数据出来,它就会立即移交任务

有人知道这样的事吗

这确实是一个调度问题,所以我可以尝试以更高的优先级启动预取线程,然后在发送查询后让它降低优先级。但是,我没有任何mysql调用将发送查询和接收结果分开

也许它就在那里,我只是不知道而已。请开导我

补充问题:

有人认为通过以比主线程更高的优先级运行预取线程可以解决这个问题吗?其思想是预取将立即抢占主线程并发送查询。然后它会在等待服务器回复时休眠。同时,主线程将运行

新增:当前实施的详细信息

这个程序对MySQL数据库中包含的数据执行计算。每秒增加3300万个项目。程序持续运行,处理新项目,有时重新分析旧项目。它从表中获取要分析的项列表,因此在过程(当前项)开始时,它知道它将需要的下一个项ID

由于每个项目都是独立的,因此这是多处理的理想目标。最简单的方法是在多台机器上运行程序的多个实例。该程序通过分析、重写和算法重新设计进行了高度优化。尽管如此,在不缺乏数据的情况下,单个实例仍会使用100%的CPU核心。我在两个四核工作站上运行4-8个拷贝。但以这种速度,他们必须花时间等待MySQL服务器。(服务器/DB模式的优化是另一个主题。)

我在这个过程中实现多线程只是为了避免阻塞SQL调用。这就是为什么我称之为“有限多线程”。工作线程有一个任务:发送命令并等待结果。(好的,两项任务。)

结果是有6个阻塞任务与6个表关联。其中两个读取数据,另外4个写入结果。它们非常相似,可以由一个通用的任务结构来定义。指向此任务的指针将传递给线程池管理器,线程池管理器将分配一个线程来执行此工作。主线程可以通过任务结构检查任务状态

这使得主线程代码非常简单。当它需要执行Task1时,它会等待Task1不忙,将SQL命令放入Task1并将其交给用户。当Task1不再忙时,它将包含结果(如果有)

编写结果的4个任务都很简单。当主线程继续执行下一项时,它有一个写记录的任务。当完成该项时,它确保在开始另一项之前完成上一次写入

这两个读取线程不那么琐碎。如果将读取传递给线程,然后等待结果,则不会得到任何结果。相反,这些任务会预取下一项的数据。因此,主线程来执行这个阻塞任务,检查预取是否完成;如有必要,等待预回迁完成,然后从任务中获取数据。最后,它用下一个项目ID重新发出任务

其思想是让预取任务立即发出查询并等待MySQL服务器。然后,主线程可以处理当前项,当它开始处理下一项时,它所需要的数据就在预回迁任务中

所以线程、线程池、同步、数据结构等都完成了。这一切都有效。我剩下的是一个日程安排问题

调度问题是这样的:当服务器获取下一个项目时,所有的速度增益都是在处理当前项目。我们在处理当前项之前发出预回迁任务,但如何保证它启动?操作系统调度程序不知道立即发出查询对预取任务很重要,然后它只会等待

操作系统调度程序试图做到“公平”,允许每个任务在指定的时间段内运行。我最糟糕的情况是:主线程接收其切片并发出预取,然后完成当前项,并且必须等待下一项。等待释放其剩余的时间片,因此调度程序启动预回迁线程,该线程发出
type
  TForm1 = class(TForm)
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    fLoopCounters: array[0..5] of LongWord;
    fThreads: array[0..5] of TThread;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

// TTestThread

type
  TTestThread = class(TThread)
  private
    fLoopCounterPtr: PLongWord;
  protected
    procedure Execute; override;
  public
    constructor Create(ALowerPriority: boolean; ALoopCounterPtr: PLongWord);
  end;

constructor TTestThread.Create(ALowerPriority: boolean;
  ALoopCounterPtr: PLongWord);
begin
  inherited Create(True);
  if ALowerPriority then
    Priority := tpLower;
  fLoopCounterPtr := ALoopCounterPtr;
  Resume;
end;

procedure TTestThread.Execute;
begin
  while not Terminated do
    InterlockedIncrement(PInteger(fLoopCounterPtr)^);
end;

// TForm1

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
  for i := Low(fThreads) to High(fThreads) do
//    fThreads[i] := TTestThread.Create(True, @fLoopCounters[i]);
    fThreads[i] := TTestThread.Create(i >= 4, @fLoopCounters[i]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
var
  i: integer;
begin
  for i := Low(fThreads) to High(fThreads) do begin
    if fThreads[i] <> nil then
      fThreads[i].Terminate;
  end;
  for i := Low(fThreads) to High(fThreads) do
    fThreads[i].Free;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  Label1.Caption := IntToStr(fLoopCounters[0]);
  Label2.Caption := IntToStr(fLoopCounters[1]);
  Label3.Caption := IntToStr(fLoopCounters[2]);
  Label4.Caption := IntToStr(fLoopCounters[3]);
  Label5.Caption := IntToStr(fLoopCounters[4]);
  Label6.Caption := IntToStr(fLoopCounters[5]);
end;