用线程实现计时器_用线程计时查询

用线程实现计时器

介绍 (Introduction)

我在Delphi主题区域中看到了许多问题,这些问题是需要或建议进行线程查询的。 我知道遇到了类似的需求。

This article will address some of the concepts when dealing with a multithreaded delphi database application.

本文将介绍处理多线程delphi数据库应用程序时的一些概念。

Shared resource protection

共享资源保护

Query connection from thread

从线程查询连接

Displaying thread results

显示线程结果

Sketching the problem

勾画问题

Our only remaining oracle 9 production database on a 7 years old server repeatedly lost disk access.  The oracle db has been due for replacement for a few years, but vendor issues have prevented this. A other server was setup and I moved the db.  Off course the hardware wasn't exactly the same and soon people complained about performance.  

我们在7年历史的服务器上仅存的oracle 9生产数据库反复丢失了磁盘访问权限。 Oracle数据库已被替换了几年,但是供应商的问题阻止了这种情况。 设置了另一台服务器,然后我移动了数据库。 当然,硬件并不完全相同,很快人们就抱怨性能。

This was odd, taken into account the more  recent hardware.

考虑到最新的硬件,这很奇怪。

I won't go into detail about the oracle performance tuning.  After some searching we found some differences but most eye-catching was disk sorting.  A unsorted query took 500ms, but sorted it took 8 seconds.  Playing around with sort_area_size fixed this, but after some time other connection problems occurred.

我不会详细介绍oracle性能调整。 经过一些搜索,我们发现了一些差异,但最引人注目的是磁盘排序。 未排序的查询花费了500毫秒,但排序却花费了8秒。 使用sort_area_size进行修复可以解决此问题,但是一段时间后出现了其他连接问题。

I decided to play around with some database parameters to find out what the best settings would be.  I needed something to see impact on query execution time when changing parameters.  I'm not a guru at oracle performance tuning, so i setup a test system to play around with.

我决定使用一些数据库参数来找出最佳设置。 我需要一些东西来查看更改参数时对查询执行时间的影响。 我不是Oracle性能调优专家,所以我设置了一个测试系统来试用。

Specs for the Delphi test application

Delphi测试应用程序的规格

I wanted a app which would repeatedly time the execution of a query, catching and ignoring any errors and be able to connect to any of my oracle databases.

我想要一个可以重复计时查询执行时间,捕获并忽略任何错误并能够连接到我的任何Oracle数据库的应用程序。

I also wanted to optionally save test results.

我还想选择保存测试结果。

Creating the main form

创建主窗体

The goal for this app is to highlight the threading approach to this problem.  So the design for the main form must be kept simple to reduce overhead.

该应用程序的目标是突出解决此问题的线程方法。 因此,主要表单的设计必须保持简单以减少开销。

Based on the specs i needed following:

基于规格,我需要以下几点:

entry for a database connection

数据库连接条目

entry for a query

查询条目

display for query execution times

显示查询执行时间

option to start/stop a thread

启动/停止线程的选项

display for saved resultsets

显示保存的结果集

I used a listbox for the timing results, a memo for query and saved results and edit for the db connection. Some panels, splitters and labels were added for the look.

我使用了一个列表框作为计时结果,使用了一个备忘录来查询和保存结果,并为数据库连接进行编辑。 一些面板,分配器和标签被添加到外观。

Frontend view

Code for starting a thread

启动线程的代码

The "add thread" button should start a thread with a given query on a given db.

“添加线程”按钮应在给定数据库上以给定查询启动线程。

procedure TfrmQueryTiming.btnAddThreadClick(Sender: TObject);
var dbconn: string;
begin
  // cbDB is combobox for db connections, save all unique entries
  dbconn := cbDB.text;
  if cbDB.Items.IndexOf(dbconn) = -1 then
    cbDB.Items.Add(dbconn);
  // Start thread on database with query text
  AddThread(dbconn, memQuery.Text);
end;

The structure for the results

结果的结构

I need a structure to save the timing of the queries.  I don't know how many threads will be running simultaneously and it will never be a fixed number.  The structure needs to be dynamic.  Expanding together with the number of threads being created.  A descendant of TCollection fits these requirements. The timing will be done inside a thread and saved to this collection. For protecting access to the array i will use a TCriticalSection.  

我需要一种结构来保存查询的时间。 我不知道有多少个线程将同时运行,并且永远不会是一个固定的数目。 结构必须是动态的。 与正在创建的线程数一起扩展。 TCollection的后代符合这些要求。 计时将在线程内完成并保存到此集合中。 为了保护对阵列的访问,我将使用TCriticalSection。

In multithreaded applications it is vital to protect shared resources against simultaneous changes.  

在多线程应用程序中,保护共享资源免于同时更改至关重要。

I put the shared resources into a separate unit uResources.  This not a must but allows very tight control to the resources.

我将共享资源放入一个单独的uResources单元中。 这不是必须的,但是可以非常严格地控制资源。

共享资源 (The shared resource)

用于保存查询时间的结构是TCollectionItem后代。 可以将其添加到TCollection后代中。 这允许动态添加或删除项目。
type
  // item for holding results
  TQueryTime = class(TCollectionItem)
  public
    // ID to identify the item
    ThreadId: Integer;
    // Time for the query to open
    ExecutionTime: TDateTime;
    // Hold errors or other messages
    Msg: string;
    // Database connection user/pass@db_alias
    DBConn: string;
  end;

  // Structure for holding multiple item results
  TQueryTimes = class(TCollection)
  private
    // Return timing item for specific thread
    function GetQueryItem(ThreadId: integer): TQueryTime;
  public
    // Save timing info for a thread
    procedure ReportQueryTime(aThreadId: Integer; aExecutionTime: TDateTime; aMsg, aDBConn: string);
    // Timing item for thread
    property QueryItem[ThreadId: integer]: TQueryTime read GetQueryItem;
  end;

If i would want to monitor different queries, i would have to indicate which query the result is for too.  Here I'm not going to do that as I'm only interested in the same query on different databases.

如果我想监视不同的查询,我也必须指出结果也是针对哪个查询。 这里我不打算这样做,因为我只对不同数据库上的同一查询感兴趣。

The Msg: string is for holding any errors or other info

Msg:字符串用于保存任何错误或其他信息

保护共享资源 (Protecting the shared resource)

将数组变量放在单元的实现部分中会使其他单元无法访问。 一个函数将提供对数组变量的访问。
// Return threadlocked variable for results
function LockQueryTimes: TQueryTimes;

// Unlock variable for results
procedure UnlockQueryTimes;

implementation

uses SysUtils, SyncObjs;

var
  // varaible for thread results
  mQueryTimes: TQueryTimes;
  // protecttion vor thread results variable
  mCSTimes: TCriticalSection;

// Return threadlocked variable for results
function LockQueryTimes: TQueryTimes;
begin
  // Be ware of this when using the TQueryTimes
  // A lock may succeed but it doesn't
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值