linux parallel 命令,Linux 并行处理神器 GNU Parallel 简明教程

Bash命令通常单线程运行,这意味着所有的处理工作只在单个 CPU 上执行。随着 CPU 规模的扩大以及核心数目的增加,这意味着只有一小部分的 CPU 资源用于处理任务,这样就造成了很大的资源浪费。 这种情况在进行多媒体转换(比如:图片和视频转换)以及数据压缩中经常遇到。

本文我们将介绍如何使用 GNU Parallel 程序在所有 CPU 核上并行地执行计算任务。

Parallel 介绍GNU Parallel 是一种通用的并行化程序,可以在同一台机器上或在您具有 SSH 访问权限的多台机器上轻松并行运行作业。

如果要在 4 个 CPU 上运行 32 个不同的作业,并行化的一种直接方法是在每个 CPU 上运行 8 个作业。

6004e3e7a32374ae6ec79e023b358af4.png

GNU Parallel 会在完成后生成一个新进程,并保持 CPU 处于活动状态,从而节省时间。

669f03a5405a0791b1a39a17e3f15db3.png

Parallel 安装

1. 通过包安装

•CentOS / RHEL

$ yum install parallel

•Ubuntu / Debian

$ sudo apt install parallel

2. 通过脚本安装

$ (wget -O - pi.dk/3 || curl pi.dk/3/) | bash

Parallel 使用

Parallel 语法简介

Usage:parallel [options] [command [arguments]] < list_of_argumentsparallel [options] [command [arguments]] (::: arguments|:::: argfile(s))...cat ... | parallel --pipe [options] [command [arguments]]

•Parallel 常用选项

::: 后面接参数。:::: 后面接文件。-j、--jobs   并行任务数,不想并行执行可以设为 1。若不加 -j,则预设为每个 CPU 执行一个 job。-N  每次输入的参数数量。-L N: 一次最多读取 N 行。--xargs 会在一行中输入尽可能多的参数。-xapply 从每一个源获取一个参数(或文件一行)。--header  把每一行输入中的第一个值做为参数名。-m   表示每个 job 不重复输出“背景”(context)。-X   与 -m 相反,会重复输出“背景文本”。-q  保护后面的命令。--trim lr 去除参数两头的空格,只能去除空格,换行符和 tab 都不能去除。--keep-order/-k   强制使输出与参数保持顺序 --keep-order/-k。--tmpdir/ --results   都是保存文件,但是后者可以有结构的保存。--delay  延迟每个任务启动时间。--halt  终止任务。--pipe    该参数使得我们可以将输入(stdin)分为多块(block),再将 stdin 的资料分给各个 jobs。--block  参数可以指定每块的大小。

Parallel 用法简介

1. 输入源

GNU Parallel 的输入源支持文件、命令行和标准输入( Stdin 或 Pipe)。

以命令行做为输入源。

$ parallel echo ::: a b c d e | tee a.txtabcde

以 Stdin(标准输入)作为输入源。

$ cat a.txt | parallel echoabcde

GNU Parallel 支持通过命令行指定多个输入源,它会生成所有的组合。

$ parallel echo ::: A B C ::: D E F | tee b.txtA DA EA FB DB EB FC DC EC F

多个文件作为输入,此时多个文件中的内容也会像上面那样进行组合。

$ parallel -a a.txt -a b.txt echo

Stdin(标准输入)作为文件源中的一个,使用 -, 输出结果同上。

$ cat a.txt |parallel -a - -a b.txt echo

使用 :::: 代替 -a,后面可接多个文件名。

$ cat a.txt | parallel echo :::: - b.txt

::: 和 :::: 可以同时使用,同样的输出结果也会进行组合。

$ parallel echo ::: a b :::: b.txt

当然,若不想像上面那样进行组合,可使用--xapply参数从每一个源获取一个参数(或文件一行),这个参数有些类似 R 中的函数,具有广播作用。如果其中一个输入源的长度比较短,它的值会被重复。

$ parallel --xapply echo ::: A B C ::: D E FA DB EC F$ parallel --xapply echo ::: A B C ::: D E F G H IA DB EC FA GB HC I

2. 改变参数分隔符

GNU Parallel 可以通过 --arg-sep 和 --arg-file-sep 指定分隔符替代 ::: 或 ::::,当这两个符号被其它命令占用的时候会特别有用。

$parallel -k --arg-sep ,,, echo ,,, a b ,,, c d | tee c.txta ca db cb d$parallel --xapply --arg-file-sep ,,,, echo ,,,, a.txt  b.txta A Db A Ec A Fd B De B Ea B Fb C Dc C Ed C F

3. 改变输入分隔符

GNU Parallel 默认把一行做为一个参数。使用 \n 做为参数定界符,可以使用 -d 改变。

$ parallel -d b echo :::: a.txtacde

4. 提前结束和跳过空行

GNU Parallel 支持通过 -E 参数指定一个值做为结束标志。

$ parallel -E stop echo ::: A B stop C DAB

GNU Parallel 使用 --no-run-if-empty 来跳过空行。

$ (echo 1; echo; echo 2) | parallel --no-run-if-empty echo12

5. 构建命令行

如果 Parallel 之后没有给定命令,那么这些参数会被当做命令。

$ parallel ::: ls 'echo foo' pwda.txtb.txtc.txtjianchenmypipescriptssnake_testWGS_snakefoo/home/sxuan

此外,命令还可以是一个脚本文件,一个二进制可执行文件或一个Bash的函数(须用export -f导出函数)。

$ echo "echo \$*" > s.sh$ parallel ./s.sh ::: "a b c f" "1 2 3 4"a b c f1 2 3 4

6. 替换字符串

GNU Parallel 支持多种替换字符串,默认使用 {},使用 -I 改变替换字符串符号 {}。

其最常见的字符串替换包括以下几种:

•{.},去掉扩展名•{/},去掉路径,只保留文件名•{//},只保留路径•{/.},同时去掉路径和扩展名•{#},输出任务编号

同时对于每一个字符串替换都可以自己指定符号:

•-I 对应{}•--extensionreplace 替换 {.}•--basenamereplace 替换 {/}•--dirnamereplace 替换 {//}•--basenameextensionreplace 替换 {/.}•--seqreplace 替换 {#}

$ parallel echo ::: A/B.C ; parallel echo {} ::: A/B.C ; parallel -I ,, echo ,, ::: A/B.CA/B.CA/B.CA/B.C$ parallel echo {.} ::: A/B.C ; parallel --extensionreplace ,, echo ,, ::: A/B.CA/BA/B$ parallel echo {/} ::: A/B.C ; parallel --basenamereplace ,, echo ,, ::: A/B.CB.CB.C$ parallel echo {//} ::: A/B.C ; parallel --dirnamereplace ,, echo ,, ::: A/B.CAA$ parallel echo {/.} ::: A/B.C ; parallel --basenameextensionreplace ,, echo ,, ::: A/B.CBB$ parallel echo {#} ::: A B C ; parallel --seqreplace ,, echo ,, ::: A B C123123

同时,如果有多个输入源时,可以通过 {编号} 指定某一个输入源的参数。

$ parallel --xapply  echo {1} and {2} ::: A B ::: C DA and CB and D

可以使用 / // /. 和 . 改变指定替换字符串。

$ parallel echo /={1/} //={1//} /.={1/.} .={1.} ::: A/B.C D/E.F/=B.C //=A /.=B .=A/B/=E.F //=D /.=E .=D/E

位置可以是负数,表示倒着数。

$ parallel echo 1={1} 2={2} 3={3} -1={-1} -2={-2} -3={-3} ::: A B ::: C D ::: E F1=A 2=C 3=E -1=E -2=C -3=A1=A 2=C 3=F -1=F -2=C -3=A1=A 2=D 3=E -1=E -2=D -3=A1=A 2=D 3=F -1=F -2=D -3=A1=B 2=C 3=E -1=E -2=C -3=B1=B 2=C 3=F -1=F -2=C -3=B1=B 2=D 3=E -1=E -2=D -3=B1=B 2=D 3=F -1=F -2=D -3=B

7. 按列输入和指定参数名

使用 --header 把每一行输入中的第一个值做为参数名。

$ parallel --xapply --header : echo f1={f1} f2={f2} ::: f1 A B ::: f2 C D | tee d.txtf1=A f2=Cf1=B f2=D

使用 --colsep 把文件中的行切分为列,做为输入参数。

$ perl -e 'printf "f1\tf2\nA\tB\nC\tD\n"' > tsv-file.tsv$ parallel --header : --colsep '\t' echo f1={f1} f2={f2} :::: tsv-file.tsv f1=A f2=Bf1=C f2=D

8. 多参数

--xargs 会在一行中输入尽可能多的参数(与参数字符串长度有关),通过 -s 可指定一行中参数的上限。

$ perl -e 'for(1..30000){print "$_\n"}' > num30000$ cat num30000 | parallel --xargs echo | wc -l3$ cat num30000 | parallel --xargs -s 10000 echo | wc -l17

为了获得更好的并发性,GNU Parallel 会在文件读取结束后再分发参数。

GNU Parallel 在读取完最后一个参数之后,才开始第二个任务,此时会把所有的参数平均分配到 4 个任务(如果指定了4个任务)。

第一个任务与上面使用 --xargs 的例子一样,但是第二个任务会被平均的分成 4 个任务,最终一共 5 个任务。

$ cat num30000 | parallel --jobs 4 -m echo | wc -l5

将 1-10 分参数分配到4个任务可以看得更清晰。

$ parallel --jobs 4 -m echo ::: {1..10}1 2 34 5 67 8 910

替换字符串可以是输出字符的一部分,使用 -m 参数表示每个 job 不重复输出 “背景”(context),-X 则与 -m 相反,会重复输出 “背景文本”,具体通过下面几个例子进行理解。

$ parallel --jobs 4 echo pre-{}-post ::: A B C D E F Gpre-A-postpre-B-postpre-C-postpre-D-postpre-E-postpre-F-postpre-G-post$ parallel --jobs 4 -m echo pre-{}-post ::: A B C D E F Gpre-A B-postpre-C D-postpre-E F-postpre-G-post$ parallel --jobs 4 -X echo pre-{}-post ::: A B C D E F Gpre-A-post pre-B-postpre-C-post pre-D-postpre-E-post pre-F-postpre-G-post

使用 -N 限制每行参数的个数,其中 -N0 表示一次只读取一个参数,且不输入这个参数(作为计数器来使用)。

$ parallel -N4 echo 1={1} 2={2} 3={3} ::: A B C D E F G H1=A 2=B 3=C1=E 2=F 3=G$parallel -N0 echo foo ::: 1 2 3foofoofoo

9. 引用

如果命令行中包含特殊字符,就需要使用引号保护起来。

Perl 脚本 'print "@ARGV\n"' 与 Linux 的 echo 的功能一样。

$ perl -e 'print "@ARGV\n"' AA

使用 GNU Parallel 运行这条命令的时候,Perl 命令需要用引号包起来,也可以使用 -q 保护 Perl 命令。

$ parallel perl -e 'print "@ARGV\n"' ::: This wont work$parallel -q perl -e 'print "@ARGV\n"' ::: This worksThisworks$ parallel perl -e \''print "@ARGV\n"'\' ::: This works, tooThisworks,too

10. 去除空格

使用--trim去除参数两头的空格。

$ parallel --trim r echo pre-{}-post ::: ' A 'pre- A-post$ parallel --trim l echo pre-{}-post ::: ' A 'pre-A -post$ parallel --trim lr echo pre-{}-post ::: ' A 'pre-A-post

11. 控制输出

使用 --tag 以参数做为输出前缀,使用 --tagstring 修改输出前缀。

$ parallel --tag echo foo-{} ::: A B CA   foo-AB   foo-BC   foo-C$ parallel --tagstring {}-bar echo foo-{} ::: A B CA-bar   foo-AB-bar   foo-BC-bar   foo-C

--dryrun 作用类似于 echo 。

$ parallel --dryrun echo {} ::: A B Cecho Aecho Becho C$ parallel echo {} ::: A B CABC

--verbose 则在运行之前先打印命令。

$ parallel --verbose echo {} ::: A B Cecho Aecho Becho CABC

一般来说,GNU Parallel 会延迟输出,直到一组命令执行完成。使用 --ungroup,可立刻打印输出已完成部分。

$ parallel -j2 'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end' ::: 4 2 12-start2-middle2-end1-start1-middle1-end4-start4-middle4-end$ parallel -j2 --ungroup 'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end' ::: 4 2 14-start42-start2-middle2-end1-start1-middle1-end-middle4-end

使用 --ungroup 会很快,但会导致输出错乱,一个任务的行输出可能会被另一个任务的输出截断。像上例所示,第二行输出混合了两个任务:'4-middle' '2-start'。使用 --linebuffer 避免这个问题(稍慢一点)。

4-start2-start2-middle2-end1-start1-middle1-end4-middle4-end

强制使输出与参数保持顺序 --keep-order/-k。

$ parallel -j2 -k 'printf "%s-start\n%s" {} {};sleep {};printf "%s\n" -middle;echo {}-end' ::: 4 2 14-start4-middle4-end2-start2-middle2-end1-start1-middle1-end

12. 将输出保存到文件

GNU Parallel 可以把每一个任务的输出保存到文件中,临时文件默认保存在 /tmp 中,可以使用 --tmpdir 改变(或者修改 $TMPDIR)。

$ parallel --files ::: A B C/tmp/parfmNTJ.par/tmp/parmioFz.par/tmp/pargaTxf.par$ parallel --tmpdir ~ --files ::: A B C/home/sxuan/parLEXH7.par/home/sxuan/parXsKsR.par/home/sxuan/parZxytI.par$ TMPDIR=~ parallel --files ::: A B C/home/sxuan/par2tX6C.par/home/sxuan/parorPJy.par/home/sxuan/pari5TkI.par

输出文件可以有结构的保存 --results,输出文件不仅包含标准输出(stdout)也会包含标准错误输出(stderr)。

$ parallel --results outdir echo ::: A B CABC$ tree outdir/outdir/└── 1├── A│   ├── seq│   ├── stderr│   └── stdout├── B│   ├── seq│   ├── stderr│   └── stdout└── C├── seq├── stderr└── stdout4 directories, 9 files

在使用多个变量的时候会显得很有用。

# --header : will take the first value as name and use that in the directory structure.$ parallel --header : --results outdir echo ::: f1 A B ::: f2 C DA CA DB CB D$ tree outdir/outdir/└── f1├── A│   └── f2│       ├── C│       │   ├── seq│       │   ├── stderr│       │   └── stdout│       └── D│           ├── seq│           ├── stderr│           └── stdout└── B└── f2├── C│   ├── seq│   ├── stderr│   └── stdout└── D├── seq├── stderr└── stdout9 directories, 12 files

13. 控制执行

使用 --jobs/-j 指定并行任务数。

使用 64 个任务执行 128 个休眠命令。

$ time parallel -N0 -j64 sleep 1 ::: {1..128}real    0m2.759suser    0m0.657ssys 0m1.345s

默认情况下并行任务数与 Cpu 核心数相同, 所以这条命令会比每个 Cpu 两个任务的耗时多一倍。

$ time parallel -N0 sleep 1 ::: {1..128}real    0m3.478suser    0m0.656ssys 0m1.344s# 每个 Cpu 两个任务$ time parallel -N0 --jobs 200% sleep 1 ::: {1..128}real    0m2.659suser    0m0.734ssys 0m1.423s

使用 --jobs 0 表示执行尽可能多的并行任务。

$ time parallel -N0 --jobs 0 sleep 1 ::: {1..128}real    0m2.135suser    0m0.651ssys 0m1.477s

除了基于 Cpu 使用率之外,也可以基于 Cpu 数。

$ time parallel --use-cpus-instead-of-cores -N0 sleep 1 ::: {1..128}real    1m5.499suser    0m0.950ssys 0m1.897s

14. 交互

通过使用 --interactive 在一个任务执行之前让用户决定是否执行。

$ parallel --interactive echo ::: 1 2 3echo 1 ?...yecho 2 ?...yecho 3 ?...y123

15. 耗时

当 job 有大量的 IO 操作时,为避免“惊群效应”,可使用 --delay 参数指定各个 job 开始的时间间隔。

$ parallel --delay 2.5 echo Starting {}\;date ::: 1 2 3Starting 1Tue Apr 17 15:21:41 CST 2018Starting 2Tue Apr 17 15:21:44 CST 2018Starting 3Tue Apr 17 15:21:46 CST 2018

若已知任务超过一定时间未反应则为失败则可以通过 --timeout 指定等待时间避免无谓的等待。

GNU Parallel 能计算所有任务运行时间的中位数,因此可以指定时间为中位数的倍数关系。

$ parallel --timeout 4.1 sleep {}\; echo {} ::: 2 4 6 824$ parallel --timeout 200% sleep {}\; echo {} ::: 2.1 2.2 3 7 2.32.12.22.33

16. 显示任务进度信息

GNU Parallel 有多种方式可用来动态的显示任务进度信息,如:

$ parallel --eta sleep ::: 1 3 2 2 1 3 3 2 1$ parallel --progress sleep ::: 1 3 2 2 1 3 3 2 1$ seq 1000 | parallel -j10 --bar '(echo -n {};sleep 0.1)'  2> >(zenity --progress --auto-kill --auto-close)

使用 --joblog 参数能够生成各个任务的日志文件。

$ parallel --joblog /tmp/log exit  ::: 1 2 3 0$ cat /tmp/log Seq Host    Starttime   JobRuntime  Send    Receive Exitval Signal  Command1   :   1523950890.344       0.018  0   0   1   0   exit 12   :   1523950890.350       0.014  0   0   2   0   exit 23   :   1523950890.357       0.006  0   0   3   0   exit 34   :   1523950890.363       0.006  0   0   0   0   exit 0

通过 --resume-failed 参数可以重新运行失败的任务。

--retry-failed 的作用与 --resume-failed类似,只是 --resume-failed 从命令行读取失败任务,而 --retry-failed 则是从日志文件中读取失败任务。

$ parallel --resume-failed --joblog /tmp/log exit  ::: 1 2 3 0 0 0$ cat /tmp/logSeq Host    Starttime   JobRuntime  Send    Receive Exitval Signal  Command1   :   1523950890.344       0.018  0   0   1   0   exit 12   :   1523950890.350       0.014  0   0   2   0   exit 23   :   1523950890.357       0.006  0   0   3   0   exit 34   :   1523950890.363       0.006  0   0   0   0   exit 01   :   1523951289.575       0.029  0   0   1   0   exit 12   :   1523951289.580       0.025  0   0   2   0   exit 23   :   1523951289.585       0.019  0   0   3   0   exit 35   :   1523951289.591       0.013  0   0   0   0   exit 06   :   1523951289.604       0.004  0   0   0   0   exit 0$ parallel --retry-failed --joblog /tmp/log$ cat /tmp/logSeq Host    Starttime   JobRuntime  Send    Receive Exitval Signal  Command1   :   1523950890.344       0.018  0   0   1   0   exit 12   :   1523950890.350       0.014  0   0   2   0   exit 23   :   1523950890.357       0.006  0   0   3   0   exit 34   :   1523950890.363       0.006  0   0   0   0   exit 01   :   1523951289.575       0.029  0   0   1   0   exit 12   :   1523951289.580       0.025  0   0   2   0   exit 23   :   1523951289.585       0.019  0   0   3   0   exit 35   :   1523951289.591       0.013  0   0   0   0   exit 06   :   1523951289.604       0.004  0   0   0   0   exit 01   :   1523951445.089       0.013  0   0   1   0   exit 12   :   1523951445.094       0.009  0   0   2   0   exit 23   :   1523951445.102       0.007  0   0   3   0   exit 3

17.  终止任务

GNU Parallel 支持在某一情况下(如第一个失败或成功时,或者 20% 任务失败时)终止任务。

终止任务又有两种类型:

•其一为立即终止(通过 --halt now 指定),杀死所有正在运行的任务并停止生成新的任务。•其二为稍后终止(通过 --halt soon 指定),停止生成新任务并等待正在运行任务完成。

$ parallel -j2 --halt soon,fail=1 echo {}\; exit {} ::: 0 0 1 2 3001parallel: This job failed:echo 1; exit 1parallel: Starting no more jobs. Waiting for 1 jobs to finish.2parallel: This job failed:echo 2; exit 2$ parallel -j2 --halt now,fail=1 echo {}\; exit {} ::: 0 0 1 2 3001parallel: This job failed:echo 1; exit 1$ parallel -j2 --halt soon,fail=20% echo {}\; exit {} ::: 0 1 2 3 4 5 6 7 8 901parallel: This job failed:echo 1; exit 12parallel: This job failed:echo 2; exit 2parallel: Starting no more jobs. Waiting for 1 jobs to finish.3parallel: This job failed:echo 3; exit 3$ parallel -j2 --halt now,success=1 echo {}\; exit {} ::: 1 2 3 0 4 5 61230parallel: This job succeeded:echo 0; exit 0

GNU Parallel 还支持在任务失败后重试运行 --retries。

$ parallel -k --retries 3 'echo tried {} >>/tmp/runs; echo completed {}; exit {}' ::: 1 2 0completed 1completed 2completed 0$ cat /tmp/runstried 1tried 2tried 0tried 1tried 2tried 1tried 2

关于终止信号的高级用法参考官方入门文档。

18. 资源限制

GNU Parallel 能够在开始一个新的任务前检查系统的负载情况防止过载(通过 --load 可指定负载),同时还能检查系统是否使用了交换空间 Swap(通过 --noswap 限制使用 Swap)。

$ parallel --load 100% echo load is less than {} job per cpu ::: 1load is less than 1 job per cpu$ parallel --noswap echo the system is not swapping ::: nowthe system is not swapping now

同时,对于某些占用内存较多的程序,Parallel 会检查内存只有内存满足时才启动任务(通过 --memfree 指定需要内存大小),而且在启动任务后内存不够 50% 时会杀掉最新开始的任务,直到这个任务完成再重新开始那些杀死的任务。

$ parallel --memfree 1G echo will run if more than 1 GB is ::: freewill run if more than 1 GB is free

还可以通过 --nice 来指定任务的优先级。

$ parallel --nice 17 echo this is being run with nice -n ::: 17this is being run with nice -n 17

19. 远程操作

可使用 -S host来进行远程登陆。

$ parallel -S username@$SERVER1 echo running on ::: username@$SERVER1

20. 文件传输

GNU Parallel 文件传输使用的是 Rsync。

$ echo This is input_file > input_file$ parallel -S $SERVER1 --transferfile {} cat ::: input_file

更多远程操作参见官方入门文档。

21. --pipe

--pipe 参数使得我们可以将输入(stdin)分为多块(block),然后分配给多个任务多个 Cpu 以达到负载均衡,最后的结果顺序与原始顺序一致。

使用 --block 参数可以指定每块的大小,默认为 1M。

$ perl -e 'for(1..1000000){print "$_\n"}' > num1000000$ cat num1000000 | parallel --pipe wc 165668  165668 1048571 149796  149796 1048572 149796  149796 1048572 149796  149796 1048572 149796  149796 1048572 149796  149796 1048572  85352   85352  597465

如果不关心结果顺序,只想要快速的得到结果,可使用 --round-robin 参数。

没有这个参数时每块文件都会启动一个命令,使用这个参数后会将这些文件块分配给 job 数任务(通过 --jobs 进行指定)。若想分配更为均匀还可同时指定 --block 参数。

$ cat num1000000 | parallel --pipe -j4 --round-robin wc299592  299592 2097144315464  315464 2097143149796  149796 1048572235148  235148 1646037$ cat num1000000 | parallel --pipe -j4 --block 2M --round-robin wc299593  299593 2097151315465  315465 2097150299593  299593 209715185349   85349  597444

Parallel 使用实例

下面来看一个实际的使用 Parallel 的例子可能会更容易理解一些。

•使用 Parallel 来进行 JPEG 压缩

下面是一个普通的 find 命令,用来找出当前目录中的所有 .jpg 文件,然后通过 MozJPEG 包中提供的图像压缩工具 cjpeg 对其进行处理。

$ find . -type f -name "*.jpg" -exec cjpeg -outfile LoRes/{} {} ';'

总共耗时 0m44.114s。从 top 运行结果可以看到,虽然有 8 个核可用,但实际只有单个线程在用单个核。

05a12d0e762d1ef3eabf5e09bf9a6899.png

下面用 Parallel 来运行相同的命令。

$ find . -type f -name "*.jpg" | parallel cjpeg -outfile LoRes/{} {}

这次压缩所有图像的时间缩减到了 0m10.814s。从 top 运行结果可以看到,所有 CPU 核都满负荷运行,有 8 个线程对应使用 8 个 CPU 核。

d5163a2c3a3964e86698629911259009.png

参考文档

https://www.google.comhttp://t.cn/E6KnjtP

http://t.cn/E6KB5Rr

http://t.cn/E69yv3g

http://t.cn/Rm9X2WC

http://t.cn/E6Wr74r

今日思想

什么是成功?每个人眼里的成功都不一样。我认为,成功不是别人觉得你成功就是成功,成功是一种内心深处的自我感受。我不认为自己是成功者,也不认为自己是失败者,我只是在追求内心的一些东西,在路上!

—— 雷军

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/432360.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鼠标

1. 在UE4窗口中显示或隐藏鼠标2. 默认状态下&#xff0c;鼠标移动会转动摄像机&#xff0c;调用下面这个函数后&#xff0c;只有鼠标左键按下并移动才可以移动摄像机&#xff0c; 这样就可以对UMG这样的菜单进行控制

UMG

1. 2D UMG2. 3D UMG 新建一个Actor&#xff0c;添加一个widget组件进去&#xff0c;设置其widget class即可3. pawn和3D UMG的交互 在pawn里面加一个widgetinteraction组件&#xff0c;设置交互距离和形态&#xff0c;然后使用press pointer key就可以给3DUMG设置鼠标 点击事件…

免费开通二级域名的论坛

支持绑定域名 支持挂广告 后台管理 官网&#xff1a;http://www.howbbs.com/转载于:https://www.cnblogs.com/lieyan/p/3940463.html

UProceduralMeshComponent

使用UProceduralMeshComponent可以自由的用三角星来绘制三维图形 1. 在actor的构造函数中添加UProceduralMeshComponent组件 mesh CreateDefaultSubobject<UProceduralMeshComponent>(TEXT("mesh")); Material LoadObject<UMaterial>(NULL, TEXT("…

[LeetCode] Search for a Range [34]

题目 Given a sorted array of integers, find the starting and ending position of a given target value. Your algorithms runtime complexity must be in the order of O(log n). If the target is not found in the array, return [-1, -1]. For example, Given [5, 7, 7…

linux+qt+定时精度,Qt QTimer测试定时精度

调试信息输出窗口可以查看超时误差dialog.h文件#ifndef DIALOG_H#define DIALOG_H#include #include namespace Ui {class Dialog;}class QTimer;class Dialog : public QDialog{Q_OBJECTpublic:explicit Dialog(QWidget *parent 0);~Dialog();public slots:void slotOneSec()…

最简单的基于FFmpeg的AVDevice例子(屏幕录制)

最简单的基于FFmpeg的AVDevice例子文章列表&#xff1a;最简单的基于FFmpeg的AVDevice例子&#xff08;读取摄像头&#xff09;最简单的基于FFmpeg的AVDevice例子&#xff08;屏幕录制&#xff09;&#xfeff;&#xfeff;FFmpeg中有一个和多媒体设备交互的类库&#xff1a;Li…

linux 挂载32T文件系统,linux Centos下磁盘分区及文件系统创建与挂载(示例代码)

linux Centos下磁盘分区及文件系统创建与挂载MBR(Master Boot Record)是传统的分区机制&#xff0c;应用于绝大多数使用BIOS的PC设备。1.MBR支持32bit和64bit系统2.MBR支持分区数量有限3.MBR只支持不超过2T的硬盘&#xff0c;超过2T的硬盘只能使用2T空间(使用其他方法)1.主分区…

C语言的数组初始化

http://blog.csdn.net/sibylle/article/details/2026915 一直以为 int a[256]{0};是把a的所有元素初始化为0&#xff0c;int a[256]{1};是把a所有的元素初始化为1.调试的时查看内存发现不是那么一回事.5.2.1 数组初始化 数组可以用一个列值来初始化&#xff0c;例如 …

【Modern OpenGL】第一个三角形

>说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。>强烈推荐原文&#xff0c;无论是内容还是排版。 [原文链接](http://learnopengl.com/#!Getting-started/OpenGL)本文地址&#xff1a;http://blog.csdn.net/aganlengzi…

UI Automation 简介

转载&#xff0c;源地址&#xff1a; http://blog.csdn.net/ffeiffei/article/details/6637418 MS UI Automation&#xff08;Microsoft User Interface Automation&#xff1a;UIA&#xff09;是随.net framework3.0一起发布的&#xff0c;虽然在如今这个几乎每天都有各种新名…

【OpenGL4.0】GLSL渲染语言入门与VBO、VAO使用:绘制一个三角形

以前都是用Cg的&#xff0c;现在改用GLSL&#xff0c;又要重新学&#xff0c;不过两种语言很多都是相通的。下面的例子是实现绘制一个三角形的简单程序。采用了VBO&#xff08;veretx buffer object&#xff09;、VAO&#xff08;vertex array object&#xff09;等OpenGL的一些…

catia linux下载64位,CATIA V5 CATSysDemon.exe缓冲区溢出漏洞

发布日期&#xff1a;2014-02-24更新日期&#xff1a;2014-02-25受影响系统&#xff1a;3ds catia-v5描述&#xff1a;--------------------------------------------------------------------------------CATIA是数字产品定义及生命周期管理使用的CAD、CAE、CAM应用集成软件包…

【Modern OpenGL】Shader

Shaders 正如在上一篇教程中提到的&#xff0c;shader是在GPU中运行的小程序。如上一个教程中实现的最简单的vertex shader和fragment shader&#xff0c;一个shader基本上负责图形渲染流水线中的一个阶段的功能。从根本上来说&#xff0c;shader就是将输入转化成输出的操作。而…

c语言编译的手机软件,C语言编译工具

软件介绍C语言编译工具app是一款功能十分强大的手机编译、更换代码的软件工具&#xff0c;C语言编译工具app可以快速进行代码翻译、代码查找、替换等&#xff0c;它支持多种代码语言&#xff0c;欢迎下载&#xff01;C语言编译工具app内容简单方便功能强大的代码编译器&#xf…

【Modern OpenGL】纹理 Textures

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50421006 纹理 Textures 为了使我们创建的…

HDU 2296 Ring AC自动机 + DP

题意&#xff1a;给你n个模式串&#xff0c;每个模式串有一个得分&#xff0c;让你构造出一个长度为N之内且分数最高的文本串;输出字典序列最小的。 解题思路&#xff1a; AC自动机 DP &#xff0c; 不过要输出字典序列最小&#xff0c;多开一个 一个三维字符串来辅助二维DP&…

【Modern OpenGL】转换 Transformations

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50421159 转换 Transformations 我们已经…

android studio adb 命令行,Android Studio如何配置adb以及经常使用命令

用Android Studio一年多了&#xff0c;都没有使用其调试adb,今天就分享adb配置的方法&#xff0c;分享给你们.android直接打开电脑-属性-高级配置-环境变量。web这里我用图示范给你们&#xff1a;sql这样经常使用adb就配置成功。shell紧接着还有平时经常使用的adb命令&#xff…

【Modern OpenGL】坐标系统 Coordinate Systems

说明&#xff1a;跟着learnopengl的内容学习&#xff0c;不是纯翻译&#xff0c;只是自己整理记录。 强烈推荐原文&#xff0c;无论是内容还是排版。 原文链接 本文地址&#xff1a; http://blog.csdn.net/aganlengzi/article/details/50448453 坐标系统 Coordinate Systems 在…