应用程序概述:
我有一个Delphi应用程序,允许用户定义大量查询,并在多个MySQL数据库上同时运行它们.可以一次运行的线程数量有限制(用户可以设置).用户选择要运行的查询以及运行查询的系统.每个线程使用TADOQuery组件在指定的系统上运行指定的查询.
问题描述:
当查询检索到少量记录时,即使提交了大量线程(最多约100个),应用程序也能正常工作.只要一次只运行几个线程(最多约8个),应用程序也可以处理大量记录(150,000+).但是,当用户一次运行超过10个查询(即10个以上的线程),并且每个线程正在检索大约150,000条记录时,我们就会开始出错.以下是我们目前遇到的具体错误消息:
a:Not enough storage is available to complete this operation
b:OLE error 80040E05
c:Unspecified error
d:线程创建错误:Not enough storage is available to process this command
e:Object was open
f:ODBC Driver does not support the requested properties
显然,错误是由多种因素共同造成的:线程数,每个线程检索的数据量以及可能的MySQL服务器配置.
主要问题是为什么会出现错误?我很欣赏它似乎在某种程度上与资源有关,但考虑到返回的错误不同,我想了解错误出现的原因.例如,它是由PC上的资源决定的,还是与服务器的配置有关.
后续问题是我们可以做些什么来避免出现问题?我们目前通过降低可以并发运行的线程数来限制应用程序.我们无法强制用户检索较少的记录,因为查询完全是用户定义的,如果他们想要检索200,000条记录,那么这取决于它们,因此我们无法做很多事情.实际上,我们不想降低应用程序的速度,因为大多数用户将检索少量数据,并且我们不希望使应用程序变慢以供他们使用,尽管线程数量可以由用户改变,我们宁愿找到问题的根源并尝试修复它,而不必依赖于一直调整配置.
我编写了一个应用程序(使用Delphi 2009),允许用户选择一系列可以在多个不同系统上运行的查询.为了允许查询同时运行,每个查询都使用TADOQuery对象在其自己的线程中运行.一切正常.
我遇到的问题是当我在查询仍在运行时尝试关闭应用程序时(因此单独的线程处于活动状态).当我创建每个线程时,我将线程的THandle记录在一个数组中.当我尝试关闭应用程序时,如果任何线程仍在运行,我检索线程的句柄并将其传递给TerminateThread,理论上应该终止线程并允许应用程序关闭.但是,这不会发生.主窗体的onClose事件被触发,看起来应用程序正在关闭,但是该过程保持活动状态,并且我的Delphi界面看起来好像应用程序仍在运行(即"运行"按钮变灰,调试视图处于活动状态等).在手动结束进程(Delphi中的Ctrl-F2或通过任务管理器)之前,我无法控制回Delphi.
我正在使用TerminateThread,因为查询可能需要很长时间才能运行(在我们处理一百万条记录的情况下几分钟,在最终用户环境中完全可能)并且在运行时,除非我错了,线程将无法检查Terminated属性,因此如果在查询返回之前将其设置为True,则无法自行结束,因此我无法以通常的方式终止线程(即通过检查Terminated属性).可能是用户想要在运行大型查询时退出应用程序,在这种情况下,我需要应用程序立即结束(即所有正在运行的线程立即终止),而不是强迫它们等到所有查询都有完成运行,所以TerminateThread是理想的,但它实际上并没有终止线程!
任何人都可以帮忙吗?有谁知道为什么TerminateThread无法正常工作?任何人都可以建议任何东西让线程运行大型ADO查询立即终止?
谢谢你的帮助!
应用说明:
我有一个应用程序,允许用户通过线程运行多个并发查询(一次最多100个).
我有一个用于记录错误的类.如果应用程序中发生错误,我创建该类的实例并调用过程将错误写入日志文件.
题:
我需要使错误记录代码线程安全.我注意到如果很多线程同时运行并产生相同的错误(例如无法连接到数据库),我会收到i/o错误32(由于应用程序试图写入一个文件而导致已经开放).
作为一个快速而肮脏的修复,我将写入文件的代码放入try ...除了重复循环内的块之外.如果存在异常(例如,该文件已被该类的另一个实例打开,由另一个线程启动),则它将标志设置为"false".循环继续执行,直到标志为"true"(即没有错误写入文件),如下所示:
procedure TErrorLogging.logError(error: string);
var
f: textfile;
ok: boolean;
begin
repeat
ok := true;
try
assignfile(f, fLogFilename);
if fileExists(fLogFilename) then append(f) else rewrite(f);
writeln(f, error);
closefile(f);
except
ok := false;
end;
until ok;
end;
Run Code Online (Sandbox Code Playgroud)
我知道保护代码块的正确方法是使用Critical Sections,但我不确定如何实现它,因为有许多不同的线程使用了日志记录类,并且每个实例该线程有自己的日志记录类实例,它用于写入文件(因此它们不仅仅是针对同一代码块进行同步).
选项,我可以看到它们:
我目前正在编写一个Delphi应用程序,它使用ADO在DB2数据库上运行查询.
其中一项要求是,用户应该能够使用查询日期,例如:"告诉我,从过去60天的所有数据"或"告诉我二零零九年十一月二十零日和2010年1月18日之间的所有数据"来定义.这不是问题,除了两个事实:
我需要知道的是,是否有一种有效的算法来构造从数据库中提取指定信息所需的SQL.例如,今天是1月18日,所以要从11月20日到今天提取所有信息,我需要一个类似这样的SQL语句:
SELECT data WHERE
((day >= 20) AND (month = 11) AND (year = 2009)) OR
((month = 12) AND (year = 2009)) OR
((day <= 18) AND (month = 1) AND (year = 2010))
Run Code Online (Sandbox Code Playgroud)
显然,这是一个微不足道且相对简单的示例,但如果用户想要从2008年11月而不是2009年检索数据,则查询会变得更大.
这是我构建SQL语句的唯一方法,还是有更有效的方法来做到这一点?
应用程序简介:
我编写了一个Delphi应用程序,允许用户通过MySQL数据库或DB2数据库运行查询.该应用程序使用TADOQuery组件来运行查询.
该应用程序使用一个简单的接口来构建查询字符串,允许不了解SQL的用户构建查询.用户在任何时候都不会看到任何SQL - 一切都是简单的英语,所以即使是非技术用户也能理解他们在做什么.
应用程序检查用户使用查询构建接口输入的参数,并在后台构建SQL语句,在用户实际看不到SQL本身的情况下提交它.
问题:
某些查询使用子字符串从某些字段中检索数据.当我使用SUBSTR语句时,我不会在SUBSTR语句中的逗号后面添加空格.例如,SUBSTR(字段,1,10).
这在大多数情况下都很好,但是当PC上的区域设置设置为与英语不同的区域设置时(例如荷兰语,通过Windows控制面板中的区域设置小程序更改),此形式的SUBSTR语句在运行时失败一个DB2数据库(它似乎比MySQL好).
为了让SUBSTR在该特定语言环境中正确执行,我需要在逗号后面添加空格.例如,SUBSTR(字段,1,10).
搜索SUBSTR语句的正确语法会显示带逗号和不带逗号的示例,但显然当我没有包含逗号时我发现了问题,所以我倾向于使用带空格的版本.但是,我想知道的是这是否是确定的语法,无论我是否会以这种方式使用SUBSTR出现任何问题,作为奖励,为什么我在以后不使用空格时会出现错误首先是逗号.