Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/flutter/9.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
Delphi 如何设计具有可变数据大小的FIFO队列?_Delphi_Queue_Delphi 2007_Fifo_Memory Efficient - Fatal编程技术网

Delphi 如何设计具有可变数据大小的FIFO队列?

Delphi 如何设计具有可变数据大小的FIFO队列?,delphi,queue,delphi-2007,fifo,memory-efficient,Delphi,Queue,Delphi 2007,Fifo,Memory Efficient,我只是在使用可变数据大小的FIFO队列(简单的一个,就是先推的队列,先弹出的队列),但我不确定我设计它的方式。我将在那里存储的数据类型将是预先知道的,假设对于这个类的每个实例都是相同的。我正在考虑使用TList存储具有以下定义的记录(@David-它是用于D2007的,所以我没有可用的:) 对于这样的实现(我在这里假装一切正常,所以没有使用异常处理) 我的问题是: 这是使FIFO队列(对于字符串、流、记录等数据类型)的大小从几个字节到大约1MB(对于流)的有效方法吗 非常感谢我建议使用Contn

我只是在使用可变数据大小的FIFO队列(简单的一个,就是先推的队列,先弹出的队列),但我不确定我设计它的方式。我将在那里存储的数据类型将是预先知道的,假设对于这个类的每个实例都是相同的。我正在考虑使用TList存储具有以下定义的记录(@David-它是用于D2007的,所以我没有可用的:)

对于这样的实现(我在这里假装一切正常,所以没有使用异常处理)

我的问题是:

这是使FIFO队列(对于字符串、流、记录等数据类型)的大小从几个字节到大约1MB(对于流)的有效方法吗


非常感谢

我建议使用Contnrs.pas中的内置TQueue和/或TObjectQueue。由于缺少泛型,可以为使用的每个数据类型派生一个特殊的TQueue。这将在程序的其余部分提供类型安全性,而所有与强制转换和指针相关的内容都捆绑在队列类中。

我将使用内存流和TObjectQueue(正如Uwe建议的那样)

为什么不使用:

type
  PListItem = ^TListItem;
  TListItem = record
    Size: Integer; // size of the data pointed by the following member
    Data: Pointer; // pointer to the target data reserved in memory
    Next: PListItem; // pointer to the next data entry, or nil for the last one.
  end;
您还需要一个
var Root:PListItem=nil并分配/取消分配项。您可能需要添加一个
var LastItem:PListItem=nil包含列表中的最后一项,因此您不必每次添加项目时都浏览整个列表。

虽然与现代的“基于对象的解决方案”相比仍然很原始,但对于FIFO解决方案来说,单链表仍然非常有效。不太优雅,但是,嘿,它足够好用了。如果您想要更优雅,请围绕这一切构建一个类

这对我来说没什么意义-您如何知道从队列中读取的数据类型?例如,在您的示例中,您推送(4个字符)ansistring和int-两者都是4个字节,当读回时,您如何知道它是int、str或set,或者任何适合4个字节的内容?噢,而不是
ListItem:=AllocMem(SizeOf(TListItem))我将使用
新建(列表项)mutch“cleaner”IMO.@ain-感谢
新增(列表项)关于数据类型,我忘了提到我会知道,输入什么数据类型,输出什么数据类型。我将有几个队列,每个队列只处理一种数据类型。无论如何,它可能会保存到TListItem。如果您对每种类型都有专用队列,那么我的建议是为您需要的每种类型编写一个类型安全的队列类。或者使用第三方图书馆(DeHL)。顺便说一句,别忘了切换到
Dispose()
来释放分配给
New
@ain-know-about
Dispose
,我现在正在编辑这个问题。关于第三方图书馆,我认为这类东西没有必要。现在我终于将流传递给这个队列了,在将流传递给
Push
之前,您肯定必须设置流的
SetSize
,因此我还将创建一些数据大小getter。好的,我认为代码可能是有效的。我会接受的,因为他提到了链表,这比TList本身更有效。无论如何,谢谢你对这个模棱两可的问题的所有回答;它只是用FIFO功能包装了TList。我做了一些类似的事情,除了复制推送的数据。这可能是我问题的重点;这是有效的吗?它是有效的,但在深层次的内部使用或后续使用,用于写作和阅读。我想让它尽可能简单,所以我也在考虑一个大内存流和记录列表,其中的大小和位置将被保存,但我不知道如何在弹出后删除流的开头。你会将多少项推到队列中,在什么环境下使用它?您是否在知道代码将成为瓶颈之前对其进行了优化?我经常发现,当您最终分析代码时,最简单、最容易实现的答案往往离最有效的答案不远。当其他地方出现瓶颈,完全淹没了我所做的任何优化时,我也经常手工优化代码。。。例如,当我通过网络或数据库发送数据时,它用于网络缓冲区。我想存储几种数据类型,并使用Synapse发送它们;TMemory是指向数据的指针。我的目标是在必要时删除一些数据(使用Pop方法),其中一些数据通过套接字(通过单独的方法)发送。如果使用将所有数据都放在一个流中的方法,您将不得不将所有数据从流的末尾复制到流的开头,这根本不会很快。我将首先测试这个易于实现的方法,看看您得到了什么样的性能。然后编写一个更复杂的实现,如果它是一个瓶颈。如果将其放入rawbytestring中,然后尝试确定它是记录还是其他内容,如果您希望在压平队列后查看并转储队列中的项目,这将非常难看。指向下一个数据项的指针非常好。这将使我能够脱离整个TList。尽管它不是非常面向对象的。早在1986年,我就已经在TurboPascal3.0中使用了这些列表,当时OO还是一种新的、未知的东西。我建议您将所有相关代码包装在一个新类中,使用push-and-pop方法和Root/LastItem作为此类的字段。当使用Delphi2007时,您甚至可以为这个内部列表使用一个嵌套记录,将它的大部分逻辑隐藏在外部。让它更面向对象。事实上,它不是面向对象的,这与我无关,正如你所说,它可以简单地包装到类中。我想问的是效率,从帕斯卡的角度来看,你的答案在我看来是最低的。
type
  TListQueue = class
private
  FList: TList;
public
  constructor Create;
  destructor Destroy; override;
  procedure Clear;
  procedure Push(const Value; const Size: Integer);
  procedure Pop(var Value; var Size: Integer);
end;

constructor TListQueue.Create;
begin
  inherited;
  FList := TList.Create;
end;

destructor TListQueue.Destroy;
begin
  Clear;
  FList.Free;
  inherited;
end;

procedure TListQueue.Push(const Value; const Size: Integer);
var ListItem: PListItem;
begin
  New(ListItem);
  ListItem.Size := Size;
  ListItem.Data := AllocMem(Size);
  Move(Value, ListItem.Data^, Size);
  FList.Add(ListItem);
end;

procedure TListQueue.Pop(var Value; var Size: Integer);
var ListItem: PListItem;
begin
  if FList.Count > 0 then
  begin
    ListItem := FList.Items[0];
    Size := ListItem^.Size;
    Move(ListItem.Data^, Value, ListItem.Size);
    FreeMem(ListItem.Data, ListItem.Size);
    Dispose(ListItem);
    FList.Delete(0);
  end;
end;

procedure TListQueue.Clear;
var I: Integer;
    ListItem: PListItem;
begin
  for I := 0 to FList.Count - 1 do
  begin
    ListItem := FList.Items[I];
    FreeMem(ListItem.Data, ListItem.Size);
    Dispose(ListItem);
  end;
  FList.Clear;
end;
type
  TListQueue = class
  private
    FList: TObjectQueue;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Push(const Value; const Size: Integer);
    procedure Pop(var Value; var Size: Integer);
  end;

implementation

constructor TListQueue.Create;
begin
  inherited;
  FList := TObjectQueue.Create;
end;

destructor TListQueue.Destroy;
begin
  while FList.Count > 0 do
    TMemoryStream(FList.Pop).Free;
  FreeAndNil(FList);
  inherited;
end;

procedure TListQueue.Push(const Value; const Size: Integer);
var
  LStream: TMemoryStream;
begin
  LStream := TMemoryStream.Create;
  LStream.Write(Value, Size);
  FList.Push(LStream);
end;

procedure TListQueue.Pop(var Value; var Size: Integer);
var
  LStream: TMemoryStream;
begin
  if FList.Count > 0 then
  begin
    LStream := TMemoryStream(FList.Pop);
    Size := LStream.Size;
    LStream.Position := 0;
    LStream.Read(Value, Size);
    LStream.Free;
  end;
end;
type
  PListItem = ^TListItem;
  TListItem = record
    Size: Integer; // size of the data pointed by the following member
    Data: Pointer; // pointer to the target data reserved in memory
    Next: PListItem; // pointer to the next data entry, or nil for the last one.
  end;