C Programming language
Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng
Đơn giản, nhanh, chậm, xinh, cao, thấp, giỏi, xịn… đều là những khái niệm mang tính chất tương đối. Có cái hơn khi so sánh ở góc độ này, nhưng lại kém khi so sánh ở góc độ khác. Trong ngành lập trình, mọi thứ đều là sự đánh đổi (trade off), không có giải pháp nào thỏa mãn tất cả mọi nhu cầu (silver bullet) – hoặc có nhưng chưa ai tìm ra.
Không cần bàn cãi, ai cũng đồng ý code Python dễ đọc, viết hơn C, hay… đơn giản hơn. Nhưng cái đơn giản đó, là đơn giản với con người, với lập trình viên, còn với máy tính thì hoàn toàn ngược lại.
Ta sẽ thử nghiệm chương trình đơn giản nhất trái đất: hello world viết bằng C và Python rồi so sánh dùng strace
– một công cụ debug “cao cấp” thường dùng bởi các SysAdmin.
strace
$ whatis strace strace(
1
)
- trace system calls and signals
Bài viết thực hiện trên Ubuntu 18.04, cc
– C compiler có lẽ là có sẵn. Hoặc nếu không có, hãy cài bằng sudo apt-get install -y build-essential strace
C Programming language
4 dòng code C
int
main
(
void
)
{
puts
(
“Hello world!”
);
}
Compile rồi chạy – yeah, cực đơn giản, không cần gì khác cả, cũng không cần làm việc đơn giản này trở thành rắc rôi.
$ cc hello.c -o hello# compile, sinh ra file hello
$ ./hello# chạy file hello
Hello world!
Giờ chạy với strace
để xem chương trình siêu đơn giản này gọi những system call nào, -C
sẽ hiển thị bảng thống kê, -S calls
sẽ sắp xếp thống kê này theo cột calls
, giảm dần.
$ strace -CScalls ./hello execve(
"./hello"
, ["./hello"
], 0x7fff1e9af718 /*
68
vars */)
=
0
brk(
NULL)
=
0x56174aa4e000 access(
"/etc/ld.so.nohwcap"
, F_OK)
=
-1 ENOENT(
No such file or directory)
access(
"/etc/ld.so.preload"
, R_OK)
=
-1 ENOENT(
No such file or directory)
mmap(
NULL,106420
, PROT_READ, MAP_PRIVATE,3
,0
)
=
0x7f867f8fc000 close(
3
)
=
0
access(
"/etc/ld.so.nohwcap"
, F_OK)
=
-1 ENOENT(
No such file or directory)
mprotect(
0x7f867f4e5000,2097152
, PROT_NONE)
=
0
close(
3
)
=
0
arch_prctl(
ARCH_SET_FS, 0x7f867f8fb4c0)
=
0
mprotect(
0x7f867f6e5000,16384
, PROT_READ)
=
0
mprotect(
0x56174a941000,4096
, PROT_READ)
=
0
mprotect(
0x7f867f916000,4096
, PROT_READ)
=
0
munmap(
0x7f867f8fc000,106420
)
=
0
brk(
NULL)
=
0x56174aa4e000 brk(
0x56174aa6f000)
=
0x56174aa6f000 write(
1
,"Hello world!n"
, 13Hello world!)
=
13
exit_group(
0
)
=
? +++ exited with0
+++ %time
seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ----------------0
.000
.0000000
5
mmap0
.000
.0000000
4
mprotect0
.000
.0000000
3
fstat0
.000
.0000000
3
brk0
.000
.0000000
3
3
access0
.000
.0000000
2
close0
.000
.0000000
2
openat0
.000
.0000000
1
read
0
.000
.0000000
1
write0
.000
.0000000
1
munmap0
.000
.0000000
1
execve0
.000
.0000000
1
arch_prctl ------ ----------- ----------- --------- --------- ----------------100
.000
.00000027
3
total
Có tổng cộng 27 syscall được thực hiện, 3 fail.
Python
Một chương trình Python 3.6 in ra màn hình dòng chữ hello world
tương tự:
$ strace -cScalls python3 -c'print("Hello world!")'
Hello world! %time
seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ----------------9
.220
.0002772
166
32
stat7
.960
.0002393
94
fstat7
.190
.0002163
79
read
7
.190
.0002163
68
rt_sigaction8
.090
.0002434
58
close10
.250
.0003085
57
2
openat1
.630
.0000491
43
6
lseek17
.780
.00053416
34
mmap0
.430
.0000131
18
getdents12
.620
.00037924
16
mprotect2
.430
.0000736
12
brk1
.660
.0000504
12
2
ioctl5
.030
.00015117
9
9
access0
.370
.0000111
8
lstat2
.460
.00007419
4
munmap0
.300
.0000093
3
dup0
.270
.0000083
3
1
readlink0
.230
.0000072
3
sigaltstack0
.630
.00001919
1
write0
.530
.00001616
1
rt_sigprocmask0
.000
.0000000
1
getpid0
.000
.0000000
1
execve0
.000
.0000000
1
fcntl0
.000
.0000000
1
sysinfo0
.000
.0000000
1
getuid0
.000
.0000000
1
getgid0
.000
.0000000
1
geteuid0
.000
.0000000
1
getegid0
.430
.00001313
1
arch_prctl0
.800
.00002424
1
futex0
.600
.00001818
1
set_tid_address0
.630
.00001919
1
set_robust_list0
.530
.00001616
1
prlimit640
.730
.00002222
1
getrandom ------ ----------- ----------- --------- --------- ----------------100
.000
.003004703
52
total
Do output quá dài nên ở đây thay đổi câu lệnh, để có đầy đủ output hãy chạy với option C hoa:
$ strace -CScalls python -c'print("hello world")'
Chương trình Python đơn giản này thực hiện tới 703 syscall, 52 fail.
Kết luận
27 với 703 thì cái nào “hơn”?
27 nhỏ hơn 703, còn 703 thì lớn hơn 27. Lập trình C cũng rất đơn giản, đúng không!
Vậy nên khi lập trình, luôn nhớ rằng mọi thứ đều là tương đôi, đều phải đánh đổi. Mấy em gái đã xinh mà code Python lại giỏi, chỉ có 2 khả năng xảy ra:
- 1 là thiếu cái gì đó
- 2 là học Python ở PYMI rõ ràng <3.