DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: dzg1981
今日帖子: 4
在线用户: 7
导航: 论坛 -> DELPHI技术 斑竹:liumazi,sephil  
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/2 19:27:09
标题:
分享:统计文本文件行数 浏览:1960
加入我的收藏
楼主:
统计文本文件行数

https://blog.csdn.net/dbyoung/article/details/121681353
----------------------------------------------
武汉天气不好
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/2 19:41:01
1楼: 添加了测试源码地址:
  https://github.com/dbyoung720/TextLineCount.git
----------------------------------------------
武汉天气不好
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/2 20:38:06
2楼: 单独的回车不应该算一个新行,除非是在MAC上……
因为理论上换行符:

Windows用:【回车换行】也就是【0D0A】或者【#13#10】,【\r\n】,【CRLF】
Linux用:【换行】。
MAC用:【回车】。

如果不那么严谨则控件开了Wordwarp,都可以算新的一行。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 7:07:22
3楼: Delphi11源码(TStringList 可以人为定义换行符,默认是#13#10):
此帖子包含附件:
PNG 图像
大小:49.5K
----------------------------------------------
武汉天气不好
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2021/12/3 7:41:05
4楼: procedure TForm1.Button1Click(Sender: TObject);
var
  FMyTextFile    : TextFile; // just for Text file (plain text)
  FMyBufferString: string;  // if you want have a text in each line readed
  FMyTotalLines  : integer;
  FMyFileSize    : integer;
begin
  FMyFileSize   := 0;
  FMyTotalLines := 0;
  //
  AssignFile(FMyTextFile, 'E:\Data.txt');
  try
    Reset(FMyTextFile);
    FMyFileSize := FileSize(FMyTextFile);
    //
    while not EOF(FMyTextFile) do
    begin
      inc(FMyTotalLines);
      //
      Readln(FMyTextFile); // just advance to next line
      //
      //Readln(FMyTextFile, FMyBufferString { just for read the line and advance it } );
    end;
    //
  finally
    CloseFile(FMyTextFile);
    //
    ShowMessage(          { }
      Format('File size: %d, Total lines: %d', [ { }
      FMyFileSize,          { }
      FMyTotalLines          { }
      ])          { }
      );
  end;
end;


To determine the end-of-line you can use:

System.System.SetLineBreakStyle(var T: Text; Style: TTextLineBreakStyle);
tlbsLF =  Linefeed only 
tlbsCRLF  =  Carriage return followed by Linefeed 

----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 7:52:49
5楼: @emailx45:
  If there is no 
    SetTextBuf(FMyTextFile, Buffer); 
  Readln will be slow.

I test on win10x64.
----------------------------------------------
武汉天气不好
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2021/12/3 7:56:59
6楼: READLN() is very quick for me in my i7 4770K MSWindows 10
1.000.000 lines in < 1 second
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 8:02:52
7楼: The count by Readln is also different from that count by TStringList.

FileStream method is best.
此帖子包含附件:
PNG 图像
大小:13.1K
----------------------------------------------
武汉天气不好
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
注册会员
2021/12/3 8:15:04
8楼: look, readln() is based on MSWindows API not Delphi.
so... the MS is wronged another again?
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 8:22:51
9楼: readln source code:
此帖子包含附件:
PNG 图像
大小:61.1K
----------------------------------------------
武汉天气不好
作者:
男 luckyso999 (luckyso) ★☆☆☆☆ -
盒子活跃会员
2021/12/3 10:25:17
10楼:
按此在新窗口浏览图片
----------------------------------------------
-
作者:
男 luckyso999 (luckyso) ★☆☆☆☆ -
盒子活跃会员
2021/12/3 10:26:29
11楼: 前些天做的文本文件分割,去重复,用字典大文件也很快
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/3 14:00:06
12楼: 其实行数有差异是正常的,看怎么定义什么是一行。
不考虑苹果电脑的话,还是只看换行符比较靠谱【\n】,不用考虑回车。

函数setTextBuffer的确对文本有用,不过缓存太大太小都不行,我记得16到32kb左右比较合适,但是我看了下实际的项目,似乎只在输出文件时setTextBuffer了……呃……

读的时候用的是基于TStream的自己的类,稍微快一点点。
Delphi很神奇,20年前它应该是最快的,而现在读文本无论啥Reader,Stream的ReadLn,TEXTFILE的ReadLn都不太快(对比其它语言)。各种方法里面ReadLn算最快的了……

最后测试需要注意外部条件,因为很多大多文本文件相对来说太小了。
跑第二次,基本都全加载都内存里面了。

不知道大家觉得文本文件多大算大,我这里单个5GB,6GB都有,不过很多厂商都怀旧拆分了。比如原始应该是70GB的文本,传过来都是分成2GB一个个的一堆编号文件了。

最后,对比其它语言,Delphi文本操作真的太慢了。
不知道有没有人试过,Delphi开多线程读多个文件,和单线程顺序读简直没区别。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/3 14:02:28
13楼: 呃是:setTextBuf
不是:setTextBuffer
-__-
怎么总打错。。。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 14:58:53
14楼: 我测试下来,GetTextLineCount_FS 函数性能还可以。
600M 文本文件,14181548 个文件,用时 1659 毫秒。不算慢吧?
(如果把位置信息也保存下来,快速定位行也搞定了)

CPU 够快,但磁盘 IO 肯定没有那么快。
如果要说慢,肯定是思路问题。和语言无关。
----------------------------------------------
武汉天气不好
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 16:29:12
15楼: “14181548 行”,不是“14181548 个文件”
写错了。sorry。
----------------------------------------------
武汉天气不好
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/3 17:00:45
16楼: Delphi 源代码真的是个宝藏。值得多看看!
Delphi 源代码真的是个宝藏。值得多看看!
Delphi 源代码真的是个宝藏。值得多看看!
三遍!!!

举一个亲身经历的例了:
  我在学习 SIMD 指令时,针对一个 4096X4096X32bits 的位图进行任意角度旋转。
  我的目标是希望优化到 20 毫秒以内。10 毫秒以内最佳。
  但是,无论我如何优化,都在 30 毫秒以上。
  一气之下,我注释了所有旋转代码。依然需要 30 毫秒!
  最终发现,Delphi 在内存中,创建一个 4096X4096X32bits 的位图需要 30 毫秒。
  为什么呀?我在内存中创建,又不是在磁盘上。
  调试进 Delphi 源代码 Vcl.Graphics.pas 中,终于发现:
  位图创建完毕后,Delphi 多做了一步,将画布置成白色,
  当刚创建好的时候,画布默认是黑色(内存全零,当然是黑色了):
  “PatBlt(NewImageDC, 0, 0, bmWidth, bmHeight, WHITENESS);”
  而我们习惯,在自己的代码中,又将画布置成黑色:
  “bmp.Canvas.FillRect(bmp.Canvas.ClipRect);”
  多了俩步操作,就多出来这个 30 毫秒时间了。
  将 Vcl.Graphics.pas 中,这个画布置成白色的代码注释掉,
  再将自己代码中,画布置成黑色的代码注释掉,
  创建一个 4096X4096X32bits 的位图,画布默认为黑色,用时就只需要 0 毫秒了。
  源代码地址:https://github.com/dbyoung720/ImageGray.git
----------------------------------------------
武汉天气不好
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/3 18:54:58
17楼: @dbyoung
我的项目不是取得行数,是需要处理每一行的数据……

举个实际的例子:
总共722MB文本,4个文件。类似csv格式,1行大概100个字符(字节),4个字段。
稍微需要判断一下每个字段情况比如第二个字段是B=xxxxx还是A=XXXXX,
然后几个小判断后,每行输出到另一个文本。

测试几台机器,不同的操作系统,最快的同一台Windows机器呢:
Delphi大概10秒,Go可以不到2秒,Java3-4秒,C++呢5-8秒。

除了Delphi,其它语言无论Windows还是CentOS下,多线程都稍快一些。
而Delphi的程序,Windows下单多线程无区别10秒,CentOS下多线程可以到6秒。

都是运行N次看结果,这个数据量,多运行几次可以忽略磁盘IO和偶然误差。

因为逻辑真的很简单,所以我觉得不会是你说的“肯定是思路问题。和语言无关”。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/3 19:05:32
18楼: PS:大概15年前,也测过Delphi7读写文本,当时对比的是C++(可能是VC6.0一类编译的,记不清楚了)。

那时候Delphi明显快过C++,无论是读文本,还是简单的数学运算,甚至空循环运行1000W次这种。因为性能很重要,所以一直用的Delphi。

我们不是测一下就完事儿,有些必须C++的项目,也试过C++的流,和纯C的读写。
我们也知道简化流程,专注一点,避免干扰,多设备多次数。。。

现在感觉Delphi慢,只是因为别的语言进步太大了。
有兴趣可以试试Hashmap类的容器,还是Go快不少,甚至Java内存给得足都更快(-Xmx9216m -Xms9216m 这种不要它老回收)。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 arhaha (lin) ★☆☆☆☆ -
盒子活跃会员
2021/12/3 21:58:32
19楼: 上面争论了这么多,有没有考虑过读写都用自己的大缓存呢?大数据读写,不用自己的缓存,我自己都不习惯。另外一个就是用映射文件MappedFile。影响速度的,主要在磁盘IO,所以要把磁盘IO次数尽量减少。
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/6 10:00:47
20楼: @arhaha
文件不太大的话,几百兆的话,第二次就全部进缓存了,这是操作系统干的事儿(也可能是SSD自己干的)。我观察到现象是这样的。

而且LZ测试方法,测试结果都是正确的,没什么问题。
根据LZ的测试结果,用FileStream去寻找回车换行符,其实也挺快的。

我仅提出一个观点:在Windows/Linux上,应该仅考虑换行符(\n),不考虑回车符。
理论上应这样,但是单回车符算不算产生新的一行,要看实际业务逻辑。

顺便感叹了一下Delphi效率相对没以前高了。

后来又想到一个小问题,Readln和从Stream里面查找对比,不太公平。
对TEXTFILE进行ReadLn,应该对应TStreamReader.ReadLine。
而BlockRead,才对应TFileStream.Read。.
----------------------------------------------
Bye bye DDRFAN...
作者:
男 nevergrief (孤独骑士) ★☆☆☆☆ -
盒子活跃会员
2021/12/6 13:43:12
21楼: 楼上,你所谓的Delphi速度慢,根据我的判断,其实就是申请和释放内存慢。你有没有试过10.3或者10.4(可能从10.2开始了),因为我记得delphi专门就这个问题优化过。比如你需要110M内存,当超过100M的时候,RTL直接给你申请200M,这样的不慢才怪呢。
另外再给你一个建议,测试里不要包括释放内存。因为java/go是是耍赖,实验做完了,但是内存以后再释放、不被包括在实验里,直接节省几十秒时间。至于你说的C++快,我就不懂了,为什么快?这个就只能等你的解释了。
最后,不知道你有没有使用replace函数,如果使用了,那不妨再测一下,这个函数经过大幅优化,快了10倍之多。

不过Delphi效率相对没以前高也是有可能的,建议你试试XE,那是最后一个纯windows平台的版本,它的编译器和RTL可以随便使用win汇编,不像后来的版本,为了跨平台必然牺牲效率.
同时也可以试试XE2,这个版本改成x64编译器的时候,不知道效率是进步了,还是退步了,都有可能。
至于后面的版本,编译器效率肯定是退步了,这个不用想,但RTL和内存管理却是可以持续进步的,特别是从10.3开始,进步比较大,值得一试。
有空的话,等你的测试结果哦!
----------------------------------------------
只有偏执狂才能生存!
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/6 16:55:44
22楼: @nevergrief
我也很希望是我哪里没考虑周全……
可是这些项目做了10多年了,时不时的都会想再看看,在试试。

比如上面提到的纯文本的读写,自己写个类,当时确实快了不少。
自以为处理得不错,后来才发现要兼容GBK,UTF8……改吧,兼容了,速度也和Delphi自带的基本没区别了。

至于内存方面,不会new delete几千万次。自己管理,分布申请,计算位置向里面放就会快很多。也不会给Hashmap设置不合理的初始大小等等。

哎,我只想表达各方面都想过了,试过了,还没发现大家提到哪一点是没想到的。
但是这边Delphi绞尽脑汁,那边Go嗖一下就运行完了……打击很大啊。

Delphi新版公司没买,只能个人试着用,不能用在项目上。
试过在基本的文本读写上和Delphi7速度差不太多。

其实感兴趣大家可以试试楼主的例子,没内存操作,就按行读文本,看看Go是不是很快。

至于C++,有些项目必须要用,没太多时间去慢慢试。
过去加目前结论是,简单的文件读写,自带的Hashmap类容器:

1)Delphi7 明显快过 VC6.0(不清楚C++标准,可能是98?)
2) Delphi10.x 稍不如 VS2022(默认C++14)
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/6 17:25:54
23楼: 我怎么错别字好多啊……

总之公司已经不用Delphi了,仅维护老项目。
后台用C++, Java, Go。
界面全部转WEB,当然Java,springboot jquery mybatis……bla bla bla

其实也没那么严谨,比如某个只能C++的项目需要个界面,也只能QT。
不算大数据那些,技术栈已经太多,还招不到人……

至于为什么不用Delphi,呵呵Embarcadero那连绵不绝的律师信起了很大作用。

那时候不是Embarcadero,我才到公司不太清楚。
后来Embar来了,说超过授权数量,公司又买了几套。
还是说超过授权数量,公司开始内部查谁在乱用,改WIFI密码怀疑是隔壁蹭网的在用。然后继续收律师信,超过授权数量。

收了好多年,才反应过来,他们是群发啊。
老板很不开心,正好要转Linux,就决定不用Delphi了,律师信还来。
快完全不用了,律师信还来。

前些年当面和他们亚太地区的老大反应过,他说这种诈的方式确实不应该,以后经营模式不会这样了,让我们用Delphi的要有信心。。。完了律师信还来。

又给他写了邮件反馈,估计离职了吧?反正律师信还来。
没回信,还顺便定期给我邮箱发广告。

好想叫他们人过来,自己数一数我们公司有几个开发,几个在用Delphi,自己算算超出授权几个了……

真是一顿操作猛如虎,一看比分0比5。
Delphi这么好的开发工具,现在弄成这样,他们公司功劳不小。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 arhaha (lin) ★☆☆☆☆ -
盒子活跃会员
2021/12/6 22:58:52
24楼: 上面某楼的还是没有理解我的意思。即使操作系统帮你做了缓存,请问,你难道不是还是要调用操作系统的API来获取数据吗?极端情况,我每次读一个字节,每一次都调用操作系统的API,这个调用不花时间吗?自己缓存的意思,就是一次性从操作系统那里获取xx KBytes的数据到我申请的内存中,以后使用这部分数据,就像从一个数组中读取一样的,根本无需向操作系统索取了。这样的方法,对大量数据的操作,是必须的!!!!!!
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 10:19:06
25楼: @arhaha
你好,虽然我回的是其它人的帖子,但是也提到了自己管理内存。
你说的这些是基本操作啊。
我又不能贴源代码证明(虽然我也很想),顺便让大家找问题,优化。

只靠论坛是说不清楚的,不妨用楼主的例子:

自己生成个600MB的文本文件,用楼主的代码统计行数,校准本机的耗时(设法避免电脑性能差异)。

然后设法优化,看能不能比楼主的快。

再看看Go不做任何优化,就一行行读,需要的时间是多少。

最后试一下我说的例子,把600MB的文本弄成4字段的csv,1行大概100个字符(字节),4个字段。
稍微需要判断一下每个字段情况比如第二个字段是B=xxxxx还是A=XXXXX。把满足条件和不满足条件的分别输出到2个文本。
看看同样的逻辑Delphi7/11要多久,Go要多久。

自己实验才是最可靠的。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 10:49:44
26楼: 哎,多说无益……
改了一个Go的统计行数程序,试了一下我的文件。
700MB,744万行,0.6秒不到。
此帖子包含附件:
PNG 图像
大小:56.8K
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 10:57:00
27楼: Go代码如下:
因为是在项目框架内改的程序,有些冗余的代码,删除即可。
没做任何优化。就是一行行读而已。

package main

import (
  "bufio"
  "bytes"
  "fmt"
  "golang.org/x/text/encoding/simplifiedchinese"
  "golang.org/x/text/transform"
  "io"
  "io/ioutil"
  "os"
  "path"
  "path/filepath"
  "runtime"
  "strings"
  "time"
)

const AppName = "取得文本行数"
const AppVersion = "3.30.01"
//const AppCode ="LineCount"

var doFileList []string
var subCount int

func DoOneFile(number int,SourceFile string) {
  ConsoleWriteLnGBK("%d: Counting: %s...",number,path.Base(filepath.ToSlash(SourceFile)))
  fi, err := os.Open(SourceFile)
  if err != nil {
    panic(err)
  }
  defer func(f *os.File) {
    err := f.Close()
    if err != nil {

    }
  }(fi)
  reader := bufio.NewReader(fi)
  var aCount =0
  for {
    _,_, err := reader.ReadLine()
    if err == io.EOF {
      break
    }
    if err != nil {
      panic(err)
    }
    aCount++

  }
  ConsoleWriteLnGBK("%d: Done: %s: %d line(s).", number,path.Base(filepath.ToSlash(SourceFile)),aCount)
  subCount+=aCount
}

func DoOnePath(SourcePath string) {
  fileInfoList, err := ioutil.ReadDir(SourcePath)
  if err != nil {
    panic(err)
  }
  for i := range fileInfoList {
    if !fileInfoList[i].IsDir(){
      doFileList = append(doFileList,filepath.Join(SourcePath, fileInfoList[i].Name()))
    }
  }
}

func ConsoleWriteLnGBK(aContent string, a ...interface{}) {
  if strings.ToLower(runtime.GOOS[0:3])=="win" {
    b, _ := ioutil.ReadAll(transform.NewReader(bytes.NewReader([]byte(fmt.Sprintf(aContent, a...))), simplifiedchinese.GBK.NewEncoder()))
    _, err := os.Stdout.Write(b)
    if err != nil {
      fmt.Printf("Error: %s\n", aContent)
      fmt.Printf("Error: %s\n", err)
      os.Exit(1)
    }
    fmt.Printf("\n")
  }else{
    fmt.Printf(aContent+"\n", a...)
  }
}

func main() {
  defer func() {
    if err := recover(); err != nil {
      ConsoleWriteLnGBK("Error: %s", err)
      os.Exit(1)
    }
  }()
  t1:=time.Now()

  //Golang only support UTF8,but our workflow platform only support GBK。。。
  //fmt.Fprintf(os.Stdout, "%s %s\n",AppName, AppVersion)
  ConsoleWriteLnGBK("%s %s", AppName, AppVersion)

  if cap(os.Args) < 7 {
    panic("Program Params not enough!")
  }

  InputPath := os.Args[1]
  //WorkPath := os.Args[2]
  //TaskID:= os.Args[3]
  //InstanceID:= os.Args[4]
  //ImplementID:= os.Args[5]
  fRuleName := os.Args[6]
  fRuleVersion := os.Args[7]

  if fRuleName != AppName {
    panic(fmt.Sprintf("Name not match! db:%s app:%s !", fRuleName, AppName))
  }
  if fRuleVersion != AppVersion {
    panic(fmt.Sprintf("Version not match! db:%s app:%s !", fRuleVersion, AppVersion))
  }

  fmt.Println(runtime.GOOS+" "+runtime.GOARCH+" "+runtime.Version())

  paths := strings.Split(InputPath, "|")
  for _, pathOne := range paths {
    if len(pathOne) > 0 {
      DoOnePath(pathOne)
    }
  }

  for i := range doFileList {
    DoOneFile(i,doFileList[i])
  }

  ConsoleWriteLnGBK("Total lines: %d.", subCount)
  ConsoleWriteLnGBK("Time elapsed: %s", time.Now().Sub(t1))

  fmt.Printf("Finish:\n")
}
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 11:13:25
28楼: 用Go测了几个文件,测试2主要想看看文件数量影响速度么,结果如下:
程序是单线程,见上面代码,多个文件可多线程优化速度。

722MB(4个文件),744万行,0.590秒。
722MB(1个文件),744万行,0.586秒。
688MB(20个文件),2488万行,0.742秒。
5.86GB(1个文件),1亿4565万行,5.66秒。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 11:49:54
29楼: 上面是Windows 10,i7-10870H+西数SN730。
用同一台笔记本WSL2下的Ubuntu测试结果:

722MB(4个文件),744万行,0.255秒。什么鬼……
此帖子包含附件:
PNG 图像
大小:87.1K
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/7 12:03:52
30楼: 继续Linux:
5.86GB(1个文件),1亿4565万行,2.54秒。

不想再测了,

同时回应一下上面哪位同学说Java和Go的问题。
Java因为JVM,不能认为程序结束内存就释放完了。非常对。
但Go编译的是原生程序,进程都退出了,没道理说它内存是以后再释放的哦。

PS:上面行数的测试,和内存无关。。。
----------------------------------------------
Bye bye DDRFAN...
作者:
男 luckyso999 (luckyso) ★☆☆☆☆ -
盒子活跃会员
2021/12/8 10:08:46
31楼: 这Go的效率简直太强了,我之前做一个http的api,开始是用delphi,用各种线程池各种优化,过不了压测,后来用go写了个简单的...没点问题,还有用go写日志也是
----------------------------------------------
-
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2021/12/8 11:06:02
32楼: 楼上,这个应该不是狗好,是狗的库优化得好?
----------------------------------------------
-
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/8 11:16:16
33楼: @drfan (若苗瞬)
  我在 Win10X64 下,VSCode 打开你上面给出的代码:
  错误如下图,参数应该如何传入(test.txt 在当前目录下。F:\test)?谢谢。
此帖子包含附件:
PNG 图像
大小:64.5K
----------------------------------------------
武汉天气不好
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/8 11:42:31
34楼: @dbyoung

参数1:输入目录
参数2:执行目录(输出目录)
参数3,4,5没用到。
参数6:名称
参数7:版本

命令行大概这样,注意参数是目录,不是文件:

“InPath WorkPath 1 1 1 取得文本行数 3.30.01”
----------------------------------------------
Bye bye DDRFAN...
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/8 11:55:19
35楼: 再废话几句。

Go的线程,通道,真的太好用了。
上面的例子如果是处理多文件,还可以再快一些。

N个文件就用N个线程(协程)读。
正常项目是有结果的,所以N个现场都把处理的结果放入通道。
多种结果就放多个通道。
每个通道有个专门写的线程。

处理数据,奇快无比。

然后Delphi多线程本身写起来就麻烦一些,也没有通道这概念。
找了网上一些FIFO的队列,包括环形缓存,虽然这些大神已经写得很好很完美了,但是速度和Go对比起来还是差别巨大。

Go我是新手,只会每个线程对应一个文件,不清楚如果单文件很大,比如前面5GB多那种,能怎么弄。PS:今年负责C++和Go的小伙子都辞职了,找不到人问,必要的话只能自己研究。

吃完饭我弄个多线程版本试试……
----------------------------------------------
Bye bye DDRFAN...
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/8 12:00:57
35楼: OK。运行成功。谢谢。
此帖子包含附件:
PNG 图像
大小:13.5K
----------------------------------------------
武汉天气不好
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
注册会员
2021/12/8 12:36:13
36楼: 有人要包成ZIP 一包給大家測嗎?
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/8 13:22:17
37楼: @dbyoung
我看日志只有1018毫秒。
而且你别统计go和exe文件啊,目录里只留txt。

把打印输出转GBK的地方,都改为【fmt.Printf】,显示中文就不会乱码了。

试了下多线程,
这速度超过我的SSD理论速度了,
只能认为解压后被缓存到内存咯:

722MB(4个文件),744万行:
Win:0.590秒(多线程0.218秒)。Linux:0.255秒(多线程0.117秒)。

722MB(1个文件),744万行:
Win:0.586秒。

688MB(20个文件),2488万行:
Win:0.742秒(多线程0.228秒)。Linux:没测单线程(多线程0.149秒)。

5.86GB(1个文件),1亿4565万行:
Win:5.66秒。Linux:2.44秒。
此帖子包含附件:
PNG 图像
大小:23.5K
----------------------------------------------
Bye bye DDRFAN...
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/8 14:02:19
38楼: 看了一下 GO 的 readline 源码,原理好像和 Delphi 的不太一样。
再次谢谢楼上。
此帖子包含附件:
PNG 图像
大小:7.9K
----------------------------------------------
武汉天气不好
作者:
男 dbyoung (dbyoung) ★☆☆☆☆ -
普通会员
2021/12/8 14:21:28
39楼: 如果只统计 #10 作为换行,Delphi 比 GO 还要快。
此帖子包含附件:
PNG 图像
大小:40.3K
----------------------------------------------
武汉天气不好
作者:
男 lordaeron (Terry) ★☆☆☆☆ -
注册会员
2021/12/8 23:19:52
40楼: 這種程式,整個問題核心都在DISK IO, 這個數字小了,
其它都小事了。
最直接的方式就是整檔LOAD 進MEMORY, 然後LOOP 一遍。
所以, 請找出LOAD 檔進MEMORY 的最佳方式,即為答案。
----------------------------------------------
-
作者:
男 ddrfan (若苗瞬) ▲▲▲▲△ -
注册会员
2021/12/10 0:08:12
41楼: 如果只统计 #10 作为换行,Go的代码也需要调整。
新的方式稍快一些,但只能统计行数,无法进一步处理每一行数据了。
我小测的结果(没测buffer大小是否有影响):

722MB(1个文件),744万行:
Win:0.586秒 --> 0.459秒(仅统计#10)。

5.86GB(1个文件),1亿4565万行:
Win:5.66秒 --> 3.84秒(仅统计#10)。

部分代码如下,注释掉的就是原来的ReadLine方式:

  reader := bufio.NewReader(fi)
  var myBuffer = make([]byte, 655350)
  var aCount =0
  for {
    i,_ := reader.Read(myBuffer)
    j:=0
    for {
      if j>= i {
        break
      }
      if myBuffer[j] == '\n' {
        aCount++
      }
      j++
    }
    if i<655350 {
      break
    }

    //用读行的方式来判断行数。
    //_,_, err := reader.ReadLine()
    //if err == io.EOF {
    //  break
    //} else if err != nil {
    //  panic(err)
    //}
    //aCount++
  }
此帖子包含附件:
PNG 图像
大小:16.0K
----------------------------------------------
Bye bye DDRFAN...
作者:
男 hawke2e (hawke2e) ★☆☆☆☆ -
注册会员
2021/12/10 12:34:48
42楼: 这些问题没什么意义。请问什么场景下需要考虑这些边角的性能问题?
内存分配释放影响性能? 什么场景需要考虑这问题。
强迫症发作?
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
男 hawke2e (hawke2e) ★☆☆☆☆ -
注册会员
2021/12/10 12:37:41
43楼: 是的,在你的测试里,delphi是比go慢1倍,so what,我看不出会影响什么?
网上发表这些语言比较性能的文章,无非博眼球,技术上压根没有讨论的价值。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
男 hawke2e (hawke2e) ★☆☆☆☆ -
注册会员
2021/12/10 12:58:52
44楼: 就像网上那些所谓大神,吹捧,GIL就是python大神的神笔之作,一个简洁的方案就解决了大问题。
这是水平不高的表现好不!这说明pyhon的核心设计存在问题好不!
所有设计问题都是可计算问题,都是能说出好在哪不好在哪的。
捧捧场说说好话无所谓,但误导了不少初学者;认为,追求简洁就是写代码的终极目标。
----------------------------------------------
软件是什么,相信很多人都说不清。
作者:
男 hexi (Hexi) ★☆☆☆☆ -
盒子活跃会员
2021/12/12 22:20:55
45楼: 下面这个算法应该速度更快。包括改为多线程,大家可以试试。

procedure TForm1.Button1Click(Sender: TObject);
type
  TUInt64Array=array[0..((1024*1024) div sizeof(UInt64))-1] of UInt64;
var
  FMyTextFile    : TFileStream; // just for Text file (plain text)
  FMyBuffer: array[0..1024*1024-1] of Byte;  
  FMyTotalLines  : integer;
  FMyFileSize    : integer;
  N, i, uN: Integer;
  U:UInt64;
begin
  FMyFileSize   := 0;
  FMyTotalLines := 0;
  //
  FMyTextFile    : TFileStream.Create('E:\Data.txt', fmOpenRead);
  FMyFileSize:=FMyTextFile.Size;
  while not FMyTextFile.
  try
    Reset(FMyTextFile);
    FMyFileSize := FileSize(FMyTextFile);
    //
    while FMyTextFile.Position<FMyTextFile.Size do
    begin
      N:=FMyTextFile.Read(FMyBuffer, sizeof(FMyBuffer));
      uN:=N div sizeof(UInt64);
      for i:=0 to uN-1 do
      begin
  U:=TUInt64Array(FMyBuffer)[i];
  if (U and $FFFF=$0D0A) or (U and $FFFF00=$0D0A00) or (U and $FFFF0000=$0D0A0000)  or (U and $FFFF000000=$0D0A000000)  or (U and $FFFF00000000=$0D0A00000000)  or (U and $FFFF0000000000=$0D0A0000000000) or (U and $FFFF0000000000=$0D0A0000000000)then //AnsiChar
  //if (U and $FFFFFFFF=$000D000A) or (U and $FFFFFFFF00=$000D000A00) or (U and $FFFFFFFF0000=$000D000A0000) or (U and $FFFFFFFF000000=$000D000A000000) or (U and $FFFFFFFF00000000=$000D000A00000000) then //WideChar
    Inc(FMyTotalLines);
      end;
      if N mod sizeof(UInt64)>0 then
      begin
  U:=TUInt64Array(FMyBuffer)[i];
  uN:=sizeof(UInt64)- (N mod sizeof(UInt64));
  U:=U shr (8*uN);
  if (U and $FFFF=$0D0A) or (U and $FFFF00=$0D0A00) or (U and $FFFF0000=$0D0A0000)  or (U and $FFFF000000=$0D0A000000)  or (U and $FFFF00000000=$0D0A00000000)  or (U and $FFFF0000000000=$0D0A0000000000) then //AnsiChar
  //if (U and $FFFFFFFF=$000D000A) or (U and $FFFFFFFF00=$000D000A00) or (U and $FFFFFFFF0000=$000D000A0000) or (U and $FFFFFFFF000000=$000D000A000000) then //WideChar
    Inc(FMyTotalLines);
      end;

    end;
  finally
    FMyTextFile.DisposeOf;
    ShowMessage(          { }
      Format('File size: %d, Total lines: %d', [ { }
      FMyFileSize,          { }
      FMyTotalLines          { }
      ])          { }
      );
  end;
end;
----------------------------------------------
-
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v2.1 版权所有 页面执行101.5625毫秒 RSS