草庐IT

go - 记录未知长度参数的大小控制

coder 2023-07-02 原文

问题:

现在,我正在记录我的 SQL 查询和与该查询相关的参数,但如果我的参数权重很大会发生什么情况?说100MB?

解决方案:

我想遍历 args,一旦它们超过 0.5MB,我想将 args 带到这一点并只记录它们(当然,我将在实际 SQL 查询中使用整个 args 集)。

哪里卡住了:

  1. 我发现很难找到接口(interface){}在磁盘上的大小。
  2. 如何打印? (有比 %v 更好的方法吗?)

问题主要集中在第一部分,如何找到大小,我需要知道类型,如果是数组、堆栈、堆等。

如果代码有帮助,这是我的代码结构(所有内容都位于 util 文件的 dal pkg 中):

package dal

import (
    "fmt"
)

const limitedLogArgsSizeB = 100000 // ~ 0.1MB

func parsedArgs(args ...interface{}) string {
    currentSize := 0
    var res string

    for i := 0; i < len(args); i++ {
        currentEleSize := getSizeOfElement(args[i])

        if !(currentSize+currentEleSize =< limitedLogArgsSizeB) {
            break
        }

        currentSize += currentEleSize

        res = fmt.Sprintf("%s, %v", res, args[i])
    }

    return "[" + res + "]"
}

func getSizeOfElement(interface{}) (sizeInBytes int) {

}

正如您所看到的,我希望从 parsedArgs() 返回一个如下所示的字符串:

[4378233, 33, 正确]”

为了完整起见,附带的查询:

INSERT INTO Person (id,age,is_healthy) VALUES ($0,$1,$2)

所以为了证明所有这一切的意义:

假设前两个参数正好等于我要记录的大小限制的阈值,我只会从 parsedArgs() 返回前两个参数作为这样的字符串:

[4378233, 33]”

我可以根据要求提供更多详细信息,谢谢 :)

最佳答案

获取任意值(任意数据结构)的内存大小在 Go 中并非不可能,而是“困难”。有关详细信息,请参阅 How to get memory size of variable in Go?

最简单的解决方案可能是在内存中生成要记录的数据,您可以在记录之前简单地截断它(例如,如果它是一个 string 或一个字节 slice ,只需将它 slice )。然而,这不是最温和的解决方案(速度较慢且需要更多内存)。

相反,我会以不同的方式实现您想要的。我会尝试组装要记录的数据,但我会使用一个特殊的 io.Writer 作为目标(它可能针对您的磁盘或内存缓冲区),它会跟踪写入它的字节数,一旦达到限制,它可能会丢弃更多数据(或报告错误,无论您喜欢什么)。

您可以在此处看到计数 io.Writer 实现:Size in bits of object encoded to JSON?

type CounterWr struct {
    io.Writer
    Count int
}

func (cw *CounterWr) Write(p []byte) (n int, err error) {
    n, err = cw.Writer.Write(p)
    cw.Count += n
    return
}

我们可以很容易地把它变成一个功能有限的写手:

type LimitWriter struct {
    io.Writer
    Remaining int
}

func (lw *LimitWriter) Write(p []byte) (n int, err error) {
    if lw.Remaining == 0 {
        return 0, io.EOF
    }

    if lw.Remaining < len(p) {
        p = p[:lw.Remaining]
    }
    n, err = lw.Writer.Write(p)
    lw.Remaining -= n
    return
}

并且您可以使用 fmt.FprintXXX() 函数写入此 LimitWriter 的值。

写入内存缓冲区的示例:

buf := &bytes.Buffer{}
lw := &LimitWriter{
    Writer:     buf,
    Remaining:  20,
}

args := []interface{}{1, 2, "Looooooooooooong"}

fmt.Fprint(lw, args)
fmt.Printf("%d %q", buf.Len(), buf)

这将输出(在 Go Playground 上尝试):

20 "[1 2 Looooooooooooon"

如您所见,我们的 LimitWriter 只允许写入 20 个字节(LimitWriter.Remaining),其余的都被丢弃了。

请注意,在这个示例中,我将数据组装到内存缓冲区中,但在您的日志系统中,您可以直接写入日志流,只需将其包装在 LimitWriter 中(这样您就可以完全省略内存缓冲区)。

优化提示:如果您将参数作为 slice ,您可以使用循环优化截断渲染,并在达到限制后停止打印参数。

一个这样做的例子:

buf := &bytes.Buffer{}
lw := &LimitWriter{
    Writer:    buf,
    Remaining: 20,
}

args := []interface{}{1, 2, "Loooooooooooooooong", 3, 4, 5}

io.WriteString(lw, "[")
for i, v := range args {
    if _, err := fmt.Fprint(lw, v, " "); err != nil {
        fmt.Printf("Breaking at argument %d, err: %v\n", i, err)
        break
    }
}
io.WriteString(lw, "]")

fmt.Printf("%d %q", buf.Len(), buf)

输出(在 Go Playground 上尝试):

Breaking at argument 3, err: EOF
20 "[1 2 Loooooooooooooo"

这样做的好处是,一旦达到限制,我们就不必生成无论如何都会被丢弃的剩余参数的字符串表示形式,从而节省了一些 CPU(和内存)资源。

关于go - 记录未知长度参数的大小控制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57357799/

有关go - 记录未知长度参数的大小控制的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby-on-rails - unicode 字符串的长度 - 2

    在我的Rails(2.3,Ruby1.8.7)应用程序中,我需要将字符串截断到一定长度。该字符串是unicode,在控制台中运行测试时,例如'א'.length,我意识到返回了双倍长度。我想要一个与编码无关的长度,以便对unicode字符串或latin1编码字符串进行相同的截断。我已经了解了Ruby的大部分unicode资料,但仍然有些一头雾水。应该如何解决这个问题? 最佳答案 Rails有一个返回多字节字符的mb_chars方法。试试unicode_string.mb_chars.slice(0,50)

  3. ruby - 如何以所有可能的方式将字符串拆分为长度最多为 3 的连续子字符串? - 2

    我试图获取一个长度在1到10之间的字符串,并输出将字符串分解为大小为1、2或3的连续子字符串的所有可能方式。例如:输入:123456将整数分割成单个字符,然后继续查找组合。该代码将返回以下所有数组。[1,2,3,4,5,6][12,3,4,5,6][1,23,4,5,6][1,2,34,5,6][1,2,3,45,6][1,2,3,4,56][12,34,5,6][12,3,45,6][12,3,4,56][1,23,45,6][1,2,34,56][1,23,4,56][12,34,56][123,4,5,6][1,234,5,6][1,2,345,6][1,2,3,456][123

  4. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  5. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  6. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  7. Ruby Readline 在向上箭头上使控制台崩溃 - 2

    当我在Rails控制台中按向上或向左箭头时,出现此错误:irb(main):001:0>/Users/me/.rvm/gems/ruby-2.0.0-p247/gems/rb-readline-0.4.2/lib/rbreadline.rb:4269:in`blockin_rl_dispatch_subseq':invalidbytesequenceinUTF-8(ArgumentError)我使用rvm来管理我的ruby​​安装。我正在使用=>ruby-2.0.0-p247[x86_64]我使用bundle来管理我的gem,并且我有rb-readline(0.4.2)(人们推荐的最少

  8. ruby - 检查方法参数的类型 - 2

    我不确定传递给方法的对象的类型是否正确。我可能会将一个字符串传递给一个只能处理整数的函数。某种运行时保证怎么样?我看不到比以下更好的选择:defsomeFixNumMangler(input)raise"wrongtype:integerrequired"unlessinput.class==FixNumother_stuffend有更好的选择吗? 最佳答案 使用Kernel#Integer在使用之前转换输入的方法。当无法以任何合理的方式将输入转换为整数时,它将引发ArgumentError。defmy_method(number)

  9. ruby - Sinatra:运行 rspec 测试时记录噪音 - 2

    Sinatra新手;我正在运行一些rspec测试,但在日志中收到了一堆不需要的噪音。如何消除日志中过多的噪音?我仔细检查了环境是否设置为:test,这意味着记录器级别应设置为WARN而不是DEBUG。spec_helper:require"./app"require"sinatra"require"rspec"require"rack/test"require"database_cleaner"require"factory_girl"set:environment,:testFactoryGirl.definition_file_paths=%w{./factories./test/

  10. ruby-on-rails - 带 Spring 锁的 Rails 4 控制台 - 2

    我正在使用Ruby2.1.1和Rails4.1.0.rc1。当执行railsc时,它被锁定了。使用Ctrl-C停止,我得到以下错误日志:~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`gets':Interruptfrom~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.2/lib/spring/client/run.rb:47:in`verify_server_version'from~/.rvm/gems/ruby-2.1.1/gems/spring-1.1.

随机推荐