小编Guy*_*don的帖子

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

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

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

它通常以这种方式工作.但请注意,没有什么可以确保预取线程立即运行.我发现在主线程循环并开始等待预取之前,通常不会发送查询.

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

我真正想要发生的是主线程发送查询,然后让工作线程等待结果.使用libmysql.dll我打电话

result := mysql_query(p.SqlCon,pChar(p.query));
Run Code Online (Sandbox Code Playgroud)

在工作线程中.相反,我想让主线程调用类似的东西

mysql_threadedquery(p.SqlCon,pChar(p.query),thread);
Run Code Online (Sandbox Code Playgroud)

一旦数据消失,它将立即切换任务.

有谁知道这样的事吗?

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

也许它在那里,我只是不知道它.请赐教.

补充问题:

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

补充:当前实施的细节

该程序对MySQL DB中包含的数据执行计算.每秒有33M项目添加更多.该程序持续运行,处理新项目,有时重新分析旧项目.它从表中获取要分析的项目列表,因此在传递开始时(当前项目),它知道它将需要的下一个项目ID.

由于每个项目都是独立的,因此这是多处理的完美目标.最简单的方法是在多台计算机上运行多个程序实例.该程序通过分析,重写和算法重新设计进行了高度优化.不过,单个实例在没有数据缺乏的情况下使用100%的CPU核心.我在两个四核工作站上运行4-8份.但按照这个速度,他们必须花时间等待MySQL服务器.(优化服务器/数据库架构是另一个主题.)

我在这个过程中实现了多线程,以避免阻塞SQL调用.这就是我称之为"有限多线程"的原因.工作线程有一个任务:发送命令并等待结果.(好的,两个任务.)

事实证明,有6个阻止任务与6个表相关联.其中两个读取数据,另外四个写入结果.这些类似于足以由公共任务结构定义.指向此Task的指针被传递给线程池管理器,该管理器分配一个线程来完成工作.主线程可以通过Task结构检查任务状态.

这使得主线程代码非常简单.当它需要执行Task1时,它等待Task1不忙,将SQL命令放在Task1中并将其关闭.当Task1不再忙时,它包含结果(如果有的话).

写结果的4个任务是微不足道的.主线程有一个Task写入记录,然后继续下一个项目.完成该项后,它会确保先前的写入在启动另一个之前完成.

2个阅读线程不那么简单.将读取传递给线程然后等待结果将不会获得任何结果.相反,这些任务预取下一个项目的数据.因此,进入此阻塞任务的主线程检查预取是否已完成; 如果需要等待预取完成,则从任务中获取数据.最后,它使用NEXT Item ID重新发出Task.

想法是让预取任务立即发出查询并等待MySQL服务器.然后主线程可以处理当前项目,并且当它在下一个项目上启动时,它需要的数据位于预取任务中.

因此,线程,线程池,同步,数据结构等都已完成.这一切都有效.我剩下的是一个调度问题.

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

OS调度程序正在尝试"公平"并允许每个任务针对指定的时间片运行.我最糟糕的情况是:主线程接收其切片并发出预取,然后完成当前项目并且必须等待下一个项目.等待释放其剩余的时间片,因此调度程序启动预取线程,该线程发出查询然后等待.现在两个线程都在等待.当服务器发出查询信号时,预取线程重新启动,并请求结果(数据集)然后休眠.当服务器提供预取线程唤醒的结果时,标记任务完成并终止.最后,主线程重新启动并从完成的Task获取数据.

为了避免这种最坏情况的调度,我需要一些方法来确保在主线程继续使用当前项之前发出预取查询.到目前为止,我已经想到了三种方法:

  1. 发出预取任务后,主线程调用Sleep(0).这应该放弃剩下的时间片.然后我希望调度程序运行预取线程,它将发出查询然后等待.然后调度程序应该重新启动主线程(我希望.)听起来很糟糕,这实际上比没有好.

  2. 我可能会以比主线程更高的优先级发出预取线程.这应该导致调度程序立即运行它,即使它必须抢占主线程.它也可能有不良影响.后台工作线程获得更高优先级似乎不自然.

  3. 我可以异步发出查询.也就是说,单独发送查询以接收结果.这样我就可以让主线程使用mysql_send_query(非阻塞)发送预取并继续使用当前项.然后,当它需要下一个项目时,它将调用mysql_read_query,它将阻塞直到数据可用.

请注意,解决方案3甚至不使用工作线程.这看起来是最好的答案,但需要重写一些低级代码.我目前正在寻找这种异步客户端 - 服务器访问的示例.

我也喜欢这些方法的任何经验丰富的意见.我错过了什么,或者我做错了什么?请注意,这是所有正常工作的代码.我不是问怎么做,而是如何做得更好/更快.

mysql delphi multithreading scheduling

6
推荐指数
1
解决办法
2386
查看次数

如何关闭Windows便携设备的"转换和复制"对话框?

在Windows 7下,当我将一个mp3文件复制到我的iRiver H10时,我总是会得到一个对话框,提供"转换和复制"文件,或者"不,只是复制".mp3文件不受复制保护.H10是一个通过USB连接的mp3和wma播放器,但没有显示为驱动器号.它在Windows资源管理器中显示为连接的设备.这是一个Microsoft希望您通过其多媒体播放器访问的PlaysForSure设备,我不使用它.

如何禁用此对话框并始终只复制文件?

我希望有一个注册表项,或者可能是一个组策略设置,但我不是要修补一个dll.我的谷歌搜索发现了对话框字符串出现在wpdshell.dll中的事实.WPD显然代表Windows便携设备.

mp3 windows-media-player windows-7

5
推荐指数
0
解决办法
1629
查看次数

如何重载简单的整数Delphi函数?

使用Delphi 7,我有几个函数接受一个整数参数.这些函数对属于该对象的Text字符串进行操作.唯一的参数是Text中的字符索引或单词索引.例如,要在单词i之后或在我想要的字符Text [loc]之后检索文本的下一个单词:

function NextWord(i:Integer): String; overload;
function NextWord(loc:Integer): String; overload;
Run Code Online (Sandbox Code Playgroud)

显然,这是模棱两可的.Delphi帮助说"重载例程必须通过它们采用的参数数量或参数类型来区分." 所以我定义了两种类型:

type WordIndex = Integer;
type CharIndex = Integer;
...
function NextWord(i:WordIndex): String; overload;
function NextWord(i:CharIndex): String; overload;
Run Code Online (Sandbox Code Playgroud)

但这不起作用,因为它们只是Integer的别名.

Delphi对类型的帮助区分了"类型标识","类型兼容性"和"赋值兼容性",然后没有说明如何使用区别.但它确实说重复"类型"这个词来创建与Integer不同的新类型:

type WordIndex = type Integer;    //really, a new type
type CharIndex = type Integer;
...
function NextWord(i:WordIndex): String; overload;
function NextWord(i:CharIndex): String; overload;
...
var WordNumber: WordIndex;      //variable of new type
...
  WordStr := NextWord(WordNumber);  //call overloaded function
Run Code Online (Sandbox Code Playgroud)

令我惊讶的是,这也不起作用.编译器将WordIndex识别为单独的类型,并编译重载的函数,但在调用它声称重载是不明确的.我也尝试将函数参数更改为VAR(因为"对于var参数,正式和实际的类型必须相同."),但这没有帮助.

点击Web我读到编译器首先根据参数的数量消除重载函数的歧义,然后根据它们的大小消除歧义.我想我可以使WordIndex成为DWord而不是Integer,但我不希望它是16位,而我使用-1来表示"无效字数".

最后,我在"重载过程和函数"的帮助中找到了这个:"你可以传递一个重载的例程参数,这些参数的类型与任何例程的声明中的参数不同,但它们与参数中的参数兼容.不止一个声明....在这些情况下,当没有歧义时可以这样做时,编译器会调用其参数属于范围最小的类型的例程,该范围适应调用中的实际参数.

所以我尝试了这个,它有效:

type WordIndex = -1..High(Integer);
type CharIndex …
Run Code Online (Sandbox Code Playgroud)

delphi types overloading

2
推荐指数
1
解决办法
383
查看次数

如何消除Delphi中的重复常量?

我有两个常量的代码,每个常量以不同的方式描述数组的大小:

const  ArraySize = 1024;
       ArrayBits = 10;    //2^10 = 1024 bits
Run Code Online (Sandbox Code Playgroud)

我如何用另一个来表达其中一个?编译器不允许在常量中使用Log2或LdExp.

任何版本的Delphi的答案都可以.

delphi

1
推荐指数
2
解决办法
200
查看次数