如何确保函数在Go中占用一定的时间?

时间:2016-10-15 19:21:08

标签: python go time sqrl

我正在Go中为SQRL客户端实施EnScrypt。该函数需要运行,直到它使用最少的CPU时间。我的Python代码如下所示:

def enscrypt_time(salt, password, seconds, n=9, r=256):
    N = 1 << n
    start = time.process_time()
    end = start + seconds
    data = acc = scrypt.hash(password, salt, N, r, 1, 32)
    i = 1
    while time.process_time() < end:
        data = scrypt.hash(password, data, N, r, 1, 32)
        acc = xor_bytes(acc, data)
        i += 1
    return i, time.process_time() - start, acc

除了process_time函数之外,将其转换为Go非常简单。 我无法使用time.Time / Timer,因为它们会测量挂钟时间(受系统上可能正在运行的所有其他内容的影响)。我需要实际使用的CPU时间,理想情况是功能,或者至少需要运行的线程或进程。

Go等效于process_time

https://docs.python.org/3/library/time.html#time.process_time

1 个答案:

答案 0 :(得分:3)

您可以使用runtime.LockOSThread()将调用goroutine连接到其当前的OS线程。这将确保不会将其他goroutine安排到此线程,因此您的goroutine将运行而不会被中断或暂停。线程锁定时,没有其他goroutine会干扰。

在此之后,您只需要一个循环,直到给定的秒数过去。您必须致电runtime.UnlockOSThread()至&#34;发布&#34;线程并使其可供其他goroutine执行,最好以defer语句完成。

见这个例子:

func runUntil(end time.Time) {
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()
    for time.Now().Before(end) {
    }
}

要让它等待2秒,它可能看起来像这样:

start := time.Now()
end := start.Add(time.Second * 2)
runUntil(end)

fmt.Println("Verify:", time.Now().Sub(start))

这打印例如:

Verify: 2.0004556s

当然,您也可以指定不到一秒钟,例如等待100毫秒:

start := time.Now()
runUntil(start.Add(time.Millisecond * 100))
fmt.Println("Verify:", time.Now().Sub(start))

输出:

Verify: 100.1278ms

你可以使用这个功能的不同版本,如果这更适合你,需要花费大量时间来等待&#34;等等。作为time.Duration的值:

func wait(d time.Duration) {
    runtime.LockOSThread()
    defer runtime.UnlockOSThread()

    for end := time.Now().Add(d); time.Now().Before(end); {
    }
}

使用此:

start = time.Now()
wait(time.Millisecond * 200)
fmt.Println("Verify:", time.Now().Sub(start))

输出:

Verify: 200.1546ms

注意:请注意,上述函数中的循环将无情地使用CPU,因为它们没有睡眠或阻塞IO,它们只会查询当前系统时间并将其与截止时间进行比较。

如果攻击者通过多次并发尝试增加系统负载会怎样?

Go运行时限制了可以同时执行goroutine的系统线程。这由runtime.GOMAXPROCS()控制,因此这已经是一个限制。它默认为可用CPU核心数,您可以随时更改它。这也会造成瓶颈,例如使用runtime.LockOSThread(),如果在任何给定时间锁定线程的数量等于GOMAXPROCS,则会阻止执行其他gorout,直到线程被解锁。

参见相关问题:

Number of threads used by Go runtime

Why does it not create many threads when many goroutines are blocked in writing file in golang?