Go和C都直接涉及系统调用(技术上,C将调用存根).
从技术上讲,write既是系统调用又是C函数(至少在许多系统上).但是,C函数只是一个调用系统调用的存根.Go不会调用此存根,它会直接调用系统调用,这意味着此处不涉及C.
我的基准测试显示,纯C系统调用比最新版本(go1.11)中的纯Go系统调用快15.82%.
我错过了什么?可能是什么原因以及如何优化它们?
基准:
走:
package main_test
import (
"syscall"
"testing"
)
func writeAll(fd int, buf []byte) error {
for len(buf) > 0 {
n, err := syscall.Write(fd, buf)
if n < 0 {
return err
}
buf = buf[n:]
}
return nil
}
func BenchmarkReadWriteGoCalls(b *testing.B) {
fds, _ := syscall.Socketpair(syscall.AF_UNIX, syscall.SOCK_STREAM, 0)
message := "hello, world!"
buffer := make([]byte, 13)
for i := 0; i < b.N; i++ {
writeAll(fds[0], []byte(message))
syscall.Read(fds[1], buffer) …Run Code Online (Sandbox Code Playgroud) 举个例子:
#include <thread>
#include <iostream>
int main() {
int a = 0;
volatile int flag = 0;
std::thread t1([&]() {
while (flag != 1);
int b = a;
std::cout << "b = " << b << std::endl;
});
std::thread t2([&]() {
a = 5;
flag = 1;
});
t1.join();
t2.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
从概念上flag = 1;可以理解,可以在此之前重新排序和执行a = 5;,因此b的结果可以是5或0。
但是,实际上,我无法在计算机上产生输出为0的结果。我们如何保证行为或指令可重复地重排?具体如何更改代码示例?
使用boost:variant:
#include <tuple>
#include <iostream>
#include <boost/variant.hpp>
template <size_t n, typename... T>
boost::variant<T...> _tuple_index(size_t i, const std::tuple<T...>& tpl) {
if (i == n)
return std::get<n>(tpl);
else if (n == sizeof...(T) - 1)
throw std::out_of_range("Out of Index");
else
return _tuple_index<(n < sizeof...(T)-1 ? n+1 : 0)>(i, tpl);
}
template <typename... T>
boost::variant<T...> tuple_index(size_t i, const std::tuple<T...>& tpl) {
return _tuple_index<0>(i, tpl);
}
template <typename T>
auto tuple_len(T &tpl) {
return std::tuple_size<T>::value;
}
int main()
{
std::tuple<std::string, double, double, int> …Run Code Online (Sandbox Code Playgroud) pass()引用参数并将其传递给reference,但是实际上调用了一个rvalue参数reference(int&)而不是reference(int &&),这里是我的代码片段:
#include <iostream>
#include <utility>
void reference(int& v) {
std::cout << "lvalue" << std::endl;
}
void reference(int&& v) {
std::cout << "rvalue" << std::endl;
}
template <typename T>
void pass(T&& v) {
reference(v);
}
int main() {
std::cout << "rvalue pass:";
pass(1);
std::cout << "lvalue pass:";
int p = 1;
pass(p);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
输出是:
rvalue pass:lvalue
lvalue pass:lvalue
Run Code Online (Sandbox Code Playgroud)
因为p根据参考折叠规则很容易理解,但为什么模板函数传递v给reference()lvalue?
我正在比较关于sync.Mutex和Go频道的性能。这是我的基准:
// go playground: https://play.golang.org/p/f_u9jHBq_Jc
const (
start = 300 // actual = start * goprocs
end = 600 // actual = end * goprocs
step = 10
)
var goprocs = runtime.GOMAXPROCS(0) // 8
// https://perf.golang.org/search?q=upload:20190819.3
func BenchmarkChanWrite(b *testing.B) {
var v int64
ch := make(chan int, 1)
ch <- 1
for i := start; i < end; i += step {
b.Run(fmt.Sprintf("goroutines-%d", i*goprocs), func(b *testing.B) {
b.SetParallelism(i)
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
<-ch
v += 1
ch …Run Code Online (Sandbox Code Playgroud) 我正在尝试构建一个基于 docker 镜像centos7
FROM centos:centos7
RUN yum -y update
RUN yum -y install gcc
RUN gcc --version
Run Code Online (Sandbox Code Playgroud)
安装的gcc是4.8:
步
4/4 : RUN gcc --version
---> Running in 70b9aa4a1f67
gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-36)
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Run Code Online (Sandbox Code Playgroud)
如何安装 gcc7?我尝试了 devtools-7,它不起作用:
FROM centos:centos7
RUN yum -y update
RUN yum …Run Code Online (Sandbox Code Playgroud) syscall write返回-1并且set errno是一个简单的例子.我对errnoif C write调用返回零或正数的状态感兴趣.对于任何情况,如果不为零,则syscall.WriteGo中的包装器将返回,其中还包括调用返回为正的情况.errerrnowrite
然而,的C man页面write调用大致介绍了errno 可能也被设置但是不确定,如果我们写零长度的缓冲区没有解释任何细节.
因此,以下案例似乎不清楚:
errnoif write调用为文件,非阻塞套接字或阻塞套接字返回0 的状态是什么?write调用返回0并且errno不是0?errnoif writecall返回正数的状态是什么?它会消极吗?我认为上面的描述指出了C write调用和Go 之间的区别syscall.Write,这对于开发人员来说还不清楚,以下是我的想法:
根据手册页,在C write调用文件和非阻塞套接字中明确定义了返回零,但是不清楚是否存在阻塞套接字的非错误条件,这将导致write()不阻塞,返回0,并且(据推测)如果重试可能会在以后成功.
确实Go直接包装系统调用write.但是,以下代码片段似乎不安全,因为written等于零是可能触发的情况,err但我们不想破坏循环:
func writeAll(fd int, buffer []byte) bool {
length := len(buffer)
for length > 0 {
written, err := syscall.Write(fd, buffer)
if …Run Code Online (Sandbox Code Playgroud) 我正在通过Go中的goroutines优化矩阵乘法.
我的基准测试显示,每行或每个元素引入并发性会大大降低性能:
goos: darwin
goarch: amd64
BenchmarkMatrixDotNaive/A.MultNaive-8 2000000 869 ns/op 0 B/op 0 allocs/op
BenchmarkMatrixDotNaive/A.ParalMultNaivePerRow-8 100000 14467 ns/op 80 B/op 9 allocs/op
BenchmarkMatrixDotNaive/A.ParalMultNaivePerElem-8 20000 77299 ns/op 528 B/op 65 allocs/op
Run Code Online (Sandbox Code Playgroud)
我知道缓存局部性的一些基本的先验知识,每个元素并发性能会降低性能.但是,为什么即使在天真的版本中,每行仍然会降低性能?
事实上,我还写了一个块/平铺优化,它的vanilla版本(没有goroutine并发)甚至比天真版本更糟糕(这里不存在,让我们首先关注天真).
我在这做错了什么?为什么?如何在这里优化?
乘法:
package naive
import (
"errors"
"sync"
)
// Errors
var (
ErrNumElements = errors.New("Error number of elements")
ErrMatrixSize = errors.New("Error size of matrix")
)
// Matrix is a 2d array
type Matrix struct {
N int
data [][]float64
}
// New a size by size matrix …Run Code Online (Sandbox Code Playgroud) 一个简单的 Go 程序,比如main.go:
package main
func main() {
println("hello, world!")
}
Run Code Online (Sandbox Code Playgroud)
然后用
go build -gcflags "-N -l" -o main main.go
Run Code Online (Sandbox Code Playgroud)
使用 GDB:
$ gdb main
GNU gdb (GDB) 8.2
(...)
Reading symbols from main...(no debugging symbols found)...done.
Loading Go Runtime support.
(gdb) source /usr/local/Cellar/go/1.11/libexec/src/runtime/runtime-gdb.py
Loading Go Runtime support.
(gdb) info files
Symbols from "/Users/changkun/Desktop/demo/main".
Local exec file:
`/Users/changkun/Desktop/demo/main', file type mach-o-x86-64.
Entry point: 0x1049e20
0x0000000001001000 - 0x000000000104dfcf is .text
0x000000000104dfe0 - 0x0000000001077344 is __TEXT.__rodata
(...)
(gdb) b *0x1049e20 …Run Code Online (Sandbox Code Playgroud) go ×5
c++ ×3
c ×2
system-calls ×2
boost ×1
centos7 ×1
concurrency ×1
docker ×1
gcc ×1
gdb ×1
goroutine ×1
performance ×1