写给宝宝看的区块链与比特币

08年经典论文《Bitcoin: A Peer-to-Peer Electronic Cash System》

我一直在研究一种完全对等的,没有可信赖的第三方的新型电子现金系统… —— 中本聪

关键词:点对点,去中心化,防篡改,无可信第三方,多方互不信任,数据存证

平时用微信/支付宝给朋友转钱,或者银行转账,是怎么保证钱真的转过去了?答:有银行/支付宝这些大公司记录着呢。

银行、支付宝这些就是中间人,我们信任它们来帮我们记账、保管钱。但是,如果世界上没有银行、没有支付宝、没有微信支付,我们怎么在网上安全地把钱转给别人,并且保证对方收到了,钱不会被乱花(比如‘双花’问题,同一笔钱花两次)?怎么保证记账的人不作弊?

区块链就是一个能制约参与者的公共记账本。注意关键词:链,公共,制约。

链,约等于链表,顺着链,要能找到普天之下所有的历史交易。这是设计区块链的根本目的。(解决双花问题,要能知道这笔钱以前有没有花过)。

公共,所有人都能访问链且有机会新增一个链节(叫区块)。记账操作是,从内存池(里面都是待确认(待上链)的交易条目)中选择一些个条目,把这些作为新区块,寻找一个nonce值,寻找的过程是机械的、消耗巨大算力的,这个过程被称为工作量证明(Proof-of-Work)。当将这个nonce与当前区块所有数据结合并进行整体哈希运算后,生成的哈希值必须满足特定条件(如以若干个零位开头)。找到产生这种哈希的nonce需要大量计算资源,闷头算就好了。但nonce的验证非常简单。一旦某个矿机算好了,就把nonce值和区块头告诉其他矿机。大多数矿机验证无误后,新区块创建成功,成为公共的。算出nonce的矿机得到一些奖励(比特币),其他矿机放弃掉原先没算完的数,在新链的基础上,重新挑选一些待确认的交易条目进行计算。

不可篡改: 一旦一个区块被大家确认并加到链上,想改它就非常非常难!为什么?因为每个区块都像连环锁,包含了前一个区块的特殊哈希值。如果你想偷偷改掉很早以前的一个交易,你就必须把从那以后的所有区块都重新算一遍,而且要在所有矿机都还没更新到新账本之前,让超过一半的矿机都认可你改过的账本。这几乎是不可能的任务。

分叉问题:节点始终以最长链为正确版本。如果两个有效区块几乎同时到达形成临时分叉,节点通常会先处理最先收到的区块,但保留另一个分支。任何节点发现工作量证明后,会扩展其中一个分支,哪个分支被延长就会变得更长,而处理较短分支的节点只需切换,放弃较短的分支,转而处理更长的获胜链。

节省磁盘空间:使用默克尔树这种高效的数据结构,将交易成对哈希,构建类似树状结构,直到顶部得到单一哈希(默克尔根)。只有默克尔根哈希被包含在区块头中并与工作量证明链接,允许从后续区块中丢弃大部分旧交易数据,只需保留根部的区块头,节省磁盘空间。

简化支付验证(SPV):SPV客户端只需下载最长工作量证明链的区块头,通过获取将交易链接到区块的默克尔分支,从全节点获取时间戳,并使用区块头和该分支,可确认交易包含在被接受的链中,无需整个区块链。

总之,在比特币网络中,作弊在计算上不可行,实现点对点的直接交易,且交易难以被计算逆转,保护卖家免受欺诈,也方便买家实施托管服务。

Q & A

区块的粒度

一次交易就是一个区块吗?

答:不是。有三个层次:1)交易是最小单位(比如单笔转账)2)区块是容器,里面包含了多个交易。3)区块链是区块串成的链条。把一段时间内(比如10分钟)发生的很多笔交易(几十笔、几百笔甚至更多)收集起来,像打包一样,计算出nonce后,就形成了一个新的 ‘区块’。

矿工之间的竞争

所有矿工算同一个数据包吗?

答:不是。矿工的选择权是区块链去中心化特性的体现。 允许矿工自由选择高手续费交易,激励他们优先处理用户愿意多付钱的交易,提高了网络处理交易的效率(用户可以通过提高手续费让交易更快被确认)

假如一串交易的发生顺序是1,2,3,4,5,6,那么矿工可以选择4,5,6而跳过1,2,3。此时交易1、2、3只是暂时留在全网共享的“待确认池”(内存池/Mempool)里,后续的矿工在打包下一个区块时,依然能看到这些交易,并可能选择打包它们。区块链不记录交易的“自然发生时间”,只记录它们被打包进哪个区块。如果交易4、5、6先被打包进区块N,而交易1、2、3被打包进区块N+1,那么在账本上:交易4、5、6 的确认时间早于 交易1、2、3

矿工之间的竞争2

有没有矿工为了每次都抢在所有人前面算出nonce值,而选择每次只挑出一个交易进行区块的创建?这是否算作弊?

答:技术上矿工可以这样做(只打包1笔交易甚至空区块),但这通常不是作弊,而是极不划算的愚蠢策略。因为很多人以为打包交易越多,计算nonce越慢。但实际计算nonce的速度与区块中的交易数量几乎无关。矿工在解题时,实际反复计算的是区块头的哈希值。

关于什么是区块头,约等于整个区块的校验值。包含了这个区块:前一区块哈希值,本区块打包了哪些交易(叫Merkle根)、区块创建时间(时间戳)、nonce等。矿工反复、疯狂的做一件事:改变Nonce → 计算区块头哈希值 → 是否等于某个特殊值,比如前18位都是0

所以无论打包1笔或4000笔交易,矿工要计算的哈希值都是80字节区块头,所以没人打空包创建空区块。

经济模型问题

奖励与货币必须一致吗?

答:是。在比特币系统中,矿工创建新区块获得的奖励必须是比特币本身,不能是别的钱。这是精心设计的:新比特币只能这样产生、矿工需要被激励、系统完全自循环

补充:代码规定:区块奖励每4年减半(如2009年奖励50 BTC → 现在6.25 BTC → 2024年后3.125 BTC)2140年左右全部挖完,之后矿工只赚交易手续费。

论文翻译:https://zhuanlan.zhihu.com/p/180315198

mempool.space

雁栖湖混饭一顿(ICBS2025 信息与工程之夜)

八月五日更新: 邀请方来收观后感辣,果然没有白吃的宴席,收集资料时发现有网上有解说稿,这给在全英文中迷失的我带来后知后觉的学术洗礼。在此贴上以飨读者: https://www.zidonghua.com.cn/news/academism/74792.html

通知来的很急,我目光灼灼的看着Schedule上面的“自助晚宴”四个大字,心想这是不可多得的学习的好机会。哪怕公共交通辗转的离谱,过去要整整三小时,我也要去赴宴。好消息是我们学校共抢来四个名额,搭着伙的打到了雁栖湖。

继续阅读“雁栖湖混饭一顿(ICBS2025 信息与工程之夜)”

BOINC: A Platform for Volunteer Computing

请求-响应循环

概括:志愿者通过客户端连接到项目服务器(也就是说,如果有人想让别人为自己的项目贡献算力,那么就需要自己有一个服务器,并且自己设置任务如何拆分),服务器下发任务,志愿者完成后把结果传回去。

  1. 客户端定期向服务器发送rpc请求,询问有没有新任务/报告已经完成的任务
  2. 如果有新任务,服务器则把任务描述和必要的输入文件打包,通过http下载给客户端
  3. 客户端下载后在本地计算,完成后把结果上传回服务器
  4. 服务器验证无误后给客户端增加积分

额外设计

  1. 由于是客户端主动发起http请求,所以防火墙不会阻挡
  2. 如果服务器宕机,客户端设计了指数退避机制,避免广播风暴

帐户管理器(AM,用户端的中控)

  • 如果想参加多个项目。只需在AM上注册一个帐号,勾选多个项目,AM自动的动态调整项目分配(依照用户设置,比如只在晚上运行 or 某项目优先级最高)

用户偏好

  • 关键词偏好:志愿者可对一系列领域关键词选择是或否,表达对特定领域 or 项目的偏好。
    • 物理、天文、亚洲……
  • 计算偏好
    • 限制CPU使用率
    • 任务运行时段
    • 磁盘内存网络的占用
    • ……

硬件异构性的应对方案

  1. 对于同一个科学应用,需要项目方编译出多个不同版本,每个版本对应一种特定的处理器+OS组合
    • win + x64
    • linux + arm64
    • ……
    • 客户端上报自己的平台环境,服务器根据此给客户端发送不同版本的程序
  2. 更精确的控制:特定版本的cpu

plan class(由项目方定义)

输入:电脑的硬件和软件描述

输出

  1. 这个App版本是否能在该电脑上运行?

  2. 如果能跑,大概需要多少CPU、GPU资源

  3. 资源运算的峰值 FLOPS大概是多少?

比如一个plan class可以规定,“只有具备了NVIDIA RTX 30系列显卡且驱动大于某个特定版本的电脑才能运行这个APP版本”

Job

app+输入文件的集合

job属性设计:flops估计(用于预测运行时间)、最大flops、ram工作集大小、磁盘使用上限、关键词

Instance

任务执行的具体单元。一个job被分成多个instance

结果验证

志愿者的设备匿名且不可控

复制验证、同质冗余、自适应复制、项目方提供自定义验证函数

运行时隔离

安装程序创建一个专门的用户来运行boinc,保护用户原有的文件

客户端还要能控制应用程序的生命周期(暂停、恢复、终止)

boinc实现了一套基于消息传递的机制,通过共享内存来实现客户端和应用程序之间的通信、发送控制指令、接收状态信息

图形化程序

让用户感到酷炫,展示计算进度

实在没有合适的APP版本怎么办

boinc包装器

提交任务

高级特性

  1. 对于运行时间很长的任务可以提前上传中间结果
  2. 如果某个job需要很大的输入文件,且这个文件会被很多instance用到,那么局部性调度——将任务分配给已经下载了这个文件的志愿者,减少网络传输。

  3. 由于不同电脑存在性能差异,服务器可根据主机性能历史,动态分配调整instance的大小,确保每个instance的运行时间都是差不多的,例如1小时

  4. 对于非cpu密集型任务的优先级调度

参数设计

一个任务除了“成功返回“,还有很多其他结局:程序崩溃、硬件故障、恶意篡改、任务丢失……

  • delay_bound( J ): 任务截止时间,超时则视为失败并重试。
  • min_quorum( J ): 验证所需成功实例数,多数一致则采纳。
  • init_ninstances( J ): 初始并行实例数,加速达成验证。
  • max_error_instances( J ): 最大允许失败次数,防止程序崩溃。
  • max_success_instances( J ): 最大允许成功次数,防止非确定性结果。

调度策略(重要)

虽然是项目服务器进行集中任务分发,但各种调度发生在客户端。因为是用户主动进行请求,客户端要多少,服务器给多少,然后服务器进行预估时间与验证正确性。

策略:

  1. 客户端:决定当前运行哪些任务
  2. 客户端:决定何时、向哪个项目请求更多任务。

  3. 服务器:根据客户端请求,选择发送哪些任务

目标:

  1. 最终完成所有任务。

  2. 最大化吞吐量 (避免空闲、按时完成、使用最佳版本)。

  3. 遵循志愿者的资源分配和偏好。

客户端:决定当前运行哪些任务

  • 资源
    • 类型:CPU 、 GPU
    • 利用率: 估计峰值 FLOPS (Whetstone for CPU, vendor estimate for GPU)
  • 任务队列:
    • 类型:待运行、执行中、挂起、抢占的任务
    • 资源需求: 每个任务对 CPU/GPU 的使用量
  • 内存占用: 估计 RAM 工作集大小 (est_wss(J))
  • 目标
    • 可行性: 任务集合满足资源和内存约束
    • 最大可行性: 在可行的前提下,尽可能多地运行任务
  • 策略:加权轮询 (WRR)
    • 权重(或叫优先级):是动态的,根据志愿者为不同项目分配的资源份额以及近期使用情况进行调整
    • 时间切片: 默认每 1 小时重新计算优先级,运行高优先级项目的任务,目的是防止某个项目长期独占资源
    • 针对截止时间,进行剩余运行时间估计
    • 静态估计: 任务 FLOP 估计 / 服务器 FLOPs/s 估计
    • 动态估计: 当前运行时间 / 已完成比例
    • 把以上二者加权平均(或单纯平均)
    • WRR 模拟: 定期模拟 WRR 执行,预测哪些任务会错过截止时间
  • EDF (最早截止时间优先)
    • 如果预测到截止时间错过,则采用 EDF 策略

优先级排序

  1. 预测会错过截止时间的任务 (EDF)
  2. GPU 任务优先于 CPU 任务
  3. 时间切片中间或未检查点的任务
  4. 使用更多 CPU 的任务
  5. 项目调度优先级高的任务

客户端:决定何时、向哪个项目请求更多任务

缓冲区存一些已经下载好的任务,留着一会用。缓冲区有B_LO (下限), B_HI (上限)。触发条件: 当前缓冲工作量 < B_LO 时,向项目服务器请求补充工作

  • 这样设计的原因:
    • 保证网络断开、服务器宕机或项目无任务时,仍有足够工作保持资源忙碌
    • 每次 RPC 获取尽可能多的任务,减少 RPC 频率,也就减轻了项目服务器压力

WRR 模拟用于估计缓冲区持续时间,以便缓冲缺口计算,(T(A)是资源实例 A 的预计使用时间)

\operatorname{shortfall}(R)=\sum_{i n s t a n c e s A \text { of } R} \max \left(0, B_{H I}-T(A)\right)

工作请求参数

  • 缓冲缺口,服务器应发送足够工作以填补缺口。req_runtime(R)

  • 空闲资源实例数,服务器应发送能充分利用这些空闲资源的任务。 req_idle(R)

  • 队列中待处理任务的预计剩余运行时间,用于估计新任务完成时间。queue_dur(R)

  • 可获取性 (Fetchability) 项目 P 是否能提供资源 R 的任务 (非暂停、非回退、有可用版本、用户允许)。

工作获取逻辑

  1. WRR 模拟,判断是否需要补充工作。
  2. 按项目调度优先级降序扫描。
  3. 找到第一个满足条件的项目 P,向其发送工作请求。
  4. “搭便车” (Piggybacking): 在其他 RPC 请求中,如果 P 是最高优先级且可获取资源 R 的项目,也请求工作。

服务器:根据客户端请求,选择发送哪些任务

Linux开发环境及应用(大三下期末复习)

待到秋来九月八,我花开后百花杀
——黄巢《咏菊》

第二章 文本文件处理、正则表达式

匹配字符串a[i]=b[j]*c[k],等号和星号两侧可以有空格

a\[i] *= *b\[j] *\* *c\[k]

如何匹配任一非中括号字符

[^][]

匹配一对中括号及其之内的东西(这对中括号内部不能有中括号)

\[[^][]*]

如何匹配空行(只有空格)

^ *

第三章 文件系统

find 三板斧:范围、条件、动作。

范围
一棵或多棵目录树

条件
-name 文件通配符 切记文件通配符两侧引号,避免shell手快进行文件名展开。匹配规则是要传进find程序的,因为不单单要在本目录下找,可能还要递归的找。
-regex 正则表达式 带路径的
-type f普通文件 d目录 l符号链接文件 c字符设备文件 b块设备文件 p管道文件
-size +n单位 -size -n单位 单位有c字符b块kMG默认是b,b是512字节
-mtime +n -n
-newer filename
动作
-print 打印路径+文件名
-exec xxxxxx {} \; 执行某一命令
-ok 与-exec的区别是对每一个符合条件的{}执行操作前都进行询问

解释命令:find . -type d -print

从当前目录开始查找,找到所有目录并打印出路径

解释命令:find / -name “stud*” -type d -print

从当根目录开始查找,满足名字是stud开头的目录并打印出路径(两个条件是“与”的关系,且-name后的星号是文件通配符不是正则的元字符)

解释命令:find / -type -f -mtime -10 -print

从根目录开始查找,满足名字是stud开头的目录并打印出路径(两个条件是“与”的关系,且-name后的星号是文件通配符不是正则的元字符)

解释命令:find . ! -type d -link +2 -print

从当前目录查找,类型不是目录,且link数大于2的文件,打印路径

解释命令:find . -size +100k \( -name core -o -name ‘*.tmp’ \) -print

此句*.tmp 的两侧使用单双引号均可
*前可用\转义,()前也可用\转义
从当前目录开始查找,满足条件1.大小大于100k 2.名字是core或以.tmp结尾的文件,打印路径

find /lib /usr -name ‘libc*.so’ -exec ls lh {} \;

find src -name \*.c -exec frep -n — –help {} /dev/null \;

find . -type d -exec sh -c '[ -f "1"/README ] || touch "1"/README' _ {} \;

递归地在所有子目录下添加 README 文件(如果该目录下还没有 README)

find . -type d -exec sh -c '[ -f "1"/README ] || echo "# Directory:1" > "$1"/README' _ {} \;

添加内容到 README,比如写一句话或模板

find . -type f -name ‘README.md’ -delete

递归地删除所有子目录下的 README.md(无论是否存在内容)

find . -name CVS –exec rm –rf {} \; 和 find . -name CVS -print | xargs rm –rf哪个会成功、哪个会失败?

xargs可以将标准输入构造为命令的命令行参数,如果太多,可自动分批。且可以使用xargs的-n选项手动指定每批处理多少个。

rm -f .dat 文件名.dat展开失败可能的原因是什么?有什么代替命令

ls | grep “.dat$” | xargs rm -f

ls的选项:-F(早期终端没颜色时如何区分列出的是——目录/?可执行文件*?符号链接文件@?普通文件-l(等价于ll)-h(把大小转换成人可读的单位,字节数-> K或M什么的)

  • ls 和 ls * 的区别

ls 列出当前目录下的所有文件和目录。
* 代表当前目录下的所有文件和目录,ls * 列出当前目录下的所有文件(不包括目录)以及当前目录下所有目录中的内容。

  • ls -l 和 ll 的区别

如果设置了set -x,或者输入命令alias查看系统已经设置的全部别名,就会发现,ll是ls -l的别名,没有区别
# ll
+ ls –color=auto -l –color=auto

  • ls -ld 目录名 的输出是什么

该目录本身的信息,如果没有d,输出的就是目录内部的文件

当前工作目录是进程的一部分,命令:pwd打印当前目录,cd改变当前目录

  • cd后面什么都不加会发生什么?

回到用户主目录

  • 内部命令 vs 外部命令

内外是相对shell来说的,shell接收到操作员输入的一行字符串后,进行一系列加工(通配符展开)过后,最左边的单词看作命令的名字。如果这个命令是shell自己决定的,那么就是内部命令。如果需要去磁盘找可执行文件,是外部命令。
例如,cd是shell的内部命令,ls是外部命令。

mkdir, -p自动创建,rmdir

rmdir 与 rm -r 的区别

rmdir只能删除空目录(里面只能有. 和 ..),所以不怎么用。
rm -r是常用的,-r是递归的意思,把子子孙孙都删除

cp -r dir1 dir2 如果dir2存在/不存在,分别发生什么

存在:dir2新建子目录dir1,把dir1里的内容复制到dir2/dir1中
不存在:新建dir2,把dir1里的内容复制到dir2中

cp -v 冗长,了解进度
cp -u 根据时间戳增量拷贝,用于备份更新。好处:快;如果dir1和dir2写反了不会灾难
touch 修改时间戳

命令如何获取信息?硬编码是不可取的。

  • 配置文件
    • 分为:系统级偏好配置,例如bash的/etc/profile
    • 用户级偏好配置,~/.bash_profile)
  • 环境变量
    • 获取的方式:getenv
  • 命令行参数
    • 三种风格
    • (dd风格)dd if=sysdisk.img of=/dev/sdb
    • (find,gcc风格) gcc -O0 -Wall -g -masm=intel -Wa,-ahl -c shudu.c
    • (ls风格,长选项和短选项)–width=80 或 -w80
  • 交互式键盘输入
    • 这种方式在Linux命令中极少使用

STICKY权限(粘着位)能解决什么问题?

目录有写权限并且带STICKY属性,此目录下的文件仅文件主可以删除,其他用户删除操作会失败

第四章 bash脚本

脚本文件的执行有几种写法?有什么区别?

  • 三种新建子shell的执行方式:
    • bash<脚本名 (不可携带参数,其他都可携带参数)
    • bash 脚本名
    • ./脚本名(需先给脚本添加x权限,chmod u+x 脚本名)
  • 两种在当前进程中执行:
    • . 脚本名
    • source 脚本名

输入重定向符号<、<<和<<<的区别是什么

一个<:用法为 “命令 < filename”,把filename这个文件当作stdin
两个:用法为 “命令 << 定界符”,接下来可连续输入多行,直到再次遇到定界符,把这几行作为输入给到命令。其中可以使用反撇号做变量替换
三个:用法为“命令 <<< 内容”,只会取得第一个单词作为输入内容给到命令

输出重定向> >> 2>的区别是什么?

> filename 先清空(覆盖)
>> filename 追加
2> 把输出到2号文件(stderr)的内容重定向
分离stdout和stderr的意义是,程序运行时的输出可以重定向到文件,而运行过程中出现的错误可打印到屏幕上,给操作员看。如果非要把两个放一起,可以使用2<&1

我想用gcc a.c -o a > try.err 来把编译时输出的错误重定向到try.err,为什么没效果?

要使用gcc a.c -o a 2> try.err,或者 gcc a.c -o a > try.err 2>&1
但不能写为gcc a.c -o a 2>&1 > try.err

如果想使用 | more 把gcc输出的错误分屏显示,怎么办?

要使用gcc a.c -o a 2>&1 | more

在c语言程序中输出到文件时一定要先打开文件再输出吗?能不能直接指定一个数当作文件描述符?

可以。分为两种情况:
一是0,1,2是固定的,可直接使用
二是如果在运行c程序时在命令行使用“./可执行文件 5< a.txt”那么在c程序内无需打开5号文件,运行完毕后直接打开a.txt查看结果即可。注意5的后面没有空格。

引用bash变量addr的方式有{addr}和addr,区别是什么

当想拼接时,只能用${addr}AAA

当在shell中引用未定义变量时默认为空串,这很坏了,怎么使之产生一个错误?

set -u。如果取消设置即为set +u

一般情况下当前环境变量 PATH 不包括当前目录,原因何在?

在命令的组合使用中,用{}和()的区别是什么?

1.()启动子shell,{}在当前shell执行。最显著的现象就是如果有cd,那么()后当前目录不变,而{}后当前目录改变
2.()是元字符,而{}不是,是命令。所以(后可不加空格,而{后必须加空格。
3.分号的区别(1;2){1;2;} 多行可不写分号,捏成一行时要注意{后的空格和}之前的分号

第五章 进程

编写 C 语言程序,使用与下列 shell 命令相同的机制完成同样的功能
sort < aaa.txt > bbb.txt

思路:0 dup到 aaa.txt,1 dup到 bbb.txt

int main(){
    int sv;
    if (fork() == 0) {
        int fd1 = open("aaa.txt", O_RDONLY);
        dup2(fd1, 0);
        close(fd1);
        int fd2 = open("bbb.txt", O_CREAT | O_WRONLY, 0666);
        dup2(fd2, 1);
        close(fd2);
        execvp("sort");
        exit(-1);
    }
    wait(&sv);
}

编写 C 语言程序,使用与下列 shell 命令相同的机制完成同样的功能
cat aaa.txt | grep — –help

思路
进程A:执行cat aaa.txt,标准输入 -> 不变;标准输出->管道入口
进程B:执行grep — –help,标准输入 -> 管道出口;标准输出-> 不变
父进程:什么都不做

int main()
{
        int fd, sv;
        pipe(fd);
        if (fork() == 0) {
            dup2(fd[1], 1);
            close(fd[1]);
            close(fd[0]);
            execlp("cat", "a.txt", 0);
            exit(1);
        } else if (fork() == 0) {
            dup2(fd[0], 0);
            close(fd[0]);
            close(fd[1]);
            execlp("grep", "--", "--help", 0);
            exit(1);
        }
        close(fd[0]);
        close(fd[1]);
        wait(&sv);
        wait(&sv);

(样题)
编写 C 语言程序,使用与下列 shell 命令相同的机制完成同样的功能
ps -ef > proc.list; grep root < proc.list

思路
进程A:执行ps -ef,标准输入 -> 不变;标准输出->proc.list
父进程:等待进程A执行完毕后,执行grep root,标准输入 -> proc.list;标准输出 -> 不变

int main()
{
    int sv;
    if (fork() == 0) {
        int fd1 = open("proc.list", O_CREAT | O_WTONLY, 0666);
        dup2(fd1, 1);
        close(fd1);
        execlp("ps", "-ef", 0);
        exit(1);
    }
    wait(&sv);
    int fd2 = open("proc.list", O_RDONLY);
    dup2(fd2, 0);
    close(fd2);
    execlp("grep", "root", 0);
}

(上机作业四)
编写 C 语言程序,使用与下列 shell 命令相同的机制完成同样的功能
grep -v usr < /etc/passwd | wc –l > r.txt; cat r.txt

思路
进程A:执行grep -v usr,标准输入 -> /etc/passwd;标准输出->管道入口
进程B:执行wc –l,标准输入 -> 管道出口;标准输出-> r.txt
父进程:等待两个进程都执行完毕后,执行cat r.txt

人民日报:《久久为功与只争朝夕》

  最美四月天,新区建设红胜火,白洋淀水绿如蓝。7年时间,雄安新区从无到有、从蓝图到实景,一座高水平现代化城市正拔地而起,向世人展示着既要“久久为功[1]”也要“只争朝夕”的干事之道。

  习近平总书记指出:“建设雄安新区是千年大计、国家大事,既不能心浮气躁,也不能等靠要,要踏实努力,久久为功。”什么是“踏实努力”?抓住一切有利时机,利用一切有利条件,把已明确的、必须做的事紧紧抓在手上,不等不拖抓紧干。什么是“久久为功”?千年大计并非一蹴而就,必须保持足够的历史耐心和战略定力,发扬钉钉子精神,一锤接着一锤敲。读懂雄安新区建设,我们就能读懂发展理念的深刻变革,就能领悟应该树立和践行怎样的政绩观。

  雄安新区是未来之城,将是我们留给子孙后代的历史遗产,必须始终牢牢把握党中央关于雄安新区的功能定位、使命任务和原则要求,高标准高质量建设。久久为功,体现的就是一张蓝图绘到底的强大战略定力。从“把每一寸土地都规划得清清楚楚后再开工建设”,到“坚持稳步有序、量力而行,持续推进标志性疏解项目在雄安新区落地建设”,面对这样一项历史性工程,必须处理好近期目标和中远期目标等重大关系,有计划分步骤推动新区建设行稳致远。

  “时间是人类发展的空间。”中国共产党能在历史的时空中创造历史伟业,靠的就是实干。落地雄安的中国中化大厦每7天大楼“长高”一层,主体结构已实现封顶;雄安新区中关村科技园揭牌运营7个月来,累计对接企业2000余家,已有70家创新型企业进驻科技园;京雄“同城化”服务加速推进,107项服务事项实现京雄同城化办理……雄安新区的巨变,彰显了时不我待的实干精神。画出了“路线图”,定好了“时间表”,制定了“任务书”,就要拿出踏石留印、抓铁有痕的劲头,在有限时间里取得更多成果。

  为者常成,行者常至。以久久为功的韧劲,雄安新区从谋划决策到规划建设,从植树造林到管廊建设,每一步都迈得稳健扎实;以只争朝夕的干劲,雄安新区新兴产业破茧而出,高端人才持续涌入,创新高地和创业热土令人向往。久久为功与只争朝夕,相辅相成、相得益彰:坚持久久为功,方能避免心浮气躁、急功近利;强调只争朝夕,才能摒弃“等靠要”等躺平心态。既重方略也重行动,既讲耐心也讲效率,既有方向感也有紧迫感,各项工作就能不断取得新进展。

  树立“功成不必在我”的宽广胸怀,激发“功成必定有我”的历史担当,兼顾速度与质量、统筹当前与长远、正确把握显功与潜功,雄安新区更美丽的蝶变还会不断上演,中华民族永续发展的未来必将更加光明。

—— 《 人民日报 》( 2024年04月03日 第 04 版) 李 斌

[1] 久久为功,出自1989年习近平《干部的基本功–密切联系人民群众》

深圳之旅

Day-1

第一天的关键词是旅行,别的不用想,主打一个位移。清晨拉起提前收拾明白的行李一路辗转,在机场眼观六路稀里糊涂的登了基(平身)。坐地日行八万里,只缘身在飞机中。在天上也不无聊,时而鼓捣鼓捣小电视(怎么还是触摸屏),时而摆弄摆弄窗户(研究成果是能成功地调节遮光度必不是开窗通风),时而打开手机感叹一下空中wifi有点贵再把手机合上,时而做做下次要三份盒饭的美梦(先吃再颠 可真锻炼胃口)。




十里不同风 百里不同云

继续阅读“深圳之旅”