Logo

site iconJustYY | 小赖子

小赖子的英国生活和资讯,以及投资和个人生活。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

JustYY | 小赖子 RSS 预览

一日往返科茨沃尔德: 八小时车程, 遇见英国最美乡村

2026-07-22 21:38:36

去年夏天,我们从剑桥出发,自驾前往科茨沃尔德,当天往返,前后开车约八个小时。原本计划住上一晚,却因行程和天气变化改成了一日游。我们在当地乡村酒吧吃过午饭后,陆续游览了附近三个小镇,欣赏河流、石桥、古老石屋和宁静的乡村风景。虽然行程有些匆忙,但阳光下的科茨沃尔德依然给我们留下了美好而难忘的回忆。 一日往返科茨沃尔德:八小时车程,换一场英国乡村的夏日漫游 盛夏漫游科茨沃尔德:一场匆忙却美好的乡村之旅 从剑桥到科茨沃尔德:一天走过三个英国小镇 科茨沃尔德一日游:石屋、小河与英伦夏日 八小时自驾,只为看一眼科茨沃尔德的夏天 匆匆一天,慢慢回味:我们的科茨沃尔德之行 从照片里的河流、石桥、广场和石屋判断,当天去的三个地方最可能是: Bourton-on-the-Water 中文常译为“水上伯顿”。照片中有小河、石桥和很多水鸟的地方,基本可以确定是这里。 Stow-on-the-Wold 中文常译为“斯托昂泽沃尔德”。照片中的开阔广场、停车区和蜂蜜色石屋街道,很像这里的 Market Square。 Lower Slaughter 中文常译为“下斯劳特村”或“下斯劳特”。照片中的林荫小路、安静的石屋和溪流,很可能是这里;当地的小河叫 River Eye。不过也不排除其中部分照片拍摄于附近的 Upper Slaughter。 Bourton-on-the-Water:小河、低矮石桥、河边草地和水鸟,都是水上伯顿最典型的景观。 River Windrush:穿过水上伯顿中心的小河。 The Model Village:照片中成片的微型石屋和红褐色屋顶,是水上伯顿著名的九分之一比例模型村,位于 The Old New Inn 后面。 The Cotswold Pottery:照片里的橱窗上直接写着这个名字,地址位于 Bourton-on-the-Water 的 Clapton Row。 The Chestnut Tree:模型村照片中的建筑招牌,在水上伯顿也确实有这家茶室和餐厅。
去年夏天,2025年7月26日,我们从剑桥出发,开车前往科茨沃尔德(Cotswolds)。
当天我们游览了科茨沃尔德附近的三个小镇,其中印象最深的是有“小威尼斯”之称的水上伯顿(Bourton-on-the-Water)。清澈的温德拉什河(River Windrush)穿过小镇,河上分布着几座低矮的石桥。我们还参观了当地著名的模型村(The Model Village),并经过了科茨沃尔德陶艺店(The Cotswold Pottery)。
原本的计划是在那里住一晚,安排一个相对轻松的周末旅行。不过后来行程临时有了变化,印象中好像是因为天气预报不太稳定,最后决定只选天气晴朗的那一天过去,当天往返。 现在回想起来,这个决定多少有点“勇猛”:从剑桥开到科茨沃尔德,再在几个小镇之间辗转,晚上还要原路返回,一天下来足足开了八个小时。真正留给我们吃饭、散步和看风景的时间,反而没有在车上的时间长。

终于来到传说中的英国乡村

很早以前就听说过科茨沃尔德,常常被称为“英国最美的乡村”,也是很多明信片、旅游宣传照和英国乡村题材影视作品的取景地。 严格来说,科茨沃尔德并不是一个小镇,而是一大片横跨多个郡的乡村地区。这里散落着许多大大小小的村镇,它们大多保留着传统的蜂蜜色石头房屋、古老的教堂、狭窄的街道和宁静的河流。 从剑桥一路开过去并不近。等我们到达第一个小镇时,已经是下午一点多了。旅程还没有正式开始,大家便先感受到了长途驾驶带来的疲惫。 于是,我们找了一家当地比较有名的乡村酒吧,先坐下来吃午饭。 英国乡村酒吧通常都有一种很特别的氛围:外面是古老的石头房子,里面却很热闹。点上饮料和几道菜,坐下来慢慢吃,旅途的疲惫也消散了不少。那顿饭未必是整趟旅行中最重要的部分,却像一道分界线——吃完午饭,才感觉我们终于真正来到了科茨沃尔德。

一天走过三个小镇

午饭之后,我们开始在附近的小镇之间游览。当天一共开车去了三个地方,不过时隔一年,几个小镇的具体名字已经有些记不清了。 从照片来看,其中一个应该是著名的水上伯顿(Bourton-on-the-Water)。小镇中央有一条浅浅的小河穿过,河面上游着天鹅和鸭子,两岸是草地、石桥和一排排蜂蜜色的房屋。天气好的时候,河边坐满了游客,孩子们在水边玩耍,整个小镇显得格外热闹。 这个地方我们很多年前似乎也来过。再次走到河边,眼前的景色既熟悉又有些陌生。房屋、石桥和河流似乎没有发生太大变化,变化的反而是我们自己——当年还很小的孩子,如今已经长大了许多。 另外两个小镇的名字已经无法确定,只记得一路上看到了许多典型的科茨沃尔德风景:爬满绿藤的石头房屋、开满鲜花的小院、隐藏在树林中的步道,以及弯弯曲曲、只能勉强通过一辆车的乡间小路。 这里的建筑风格非常统一。墙壁大多由当地的石灰岩建成,在阳光下呈现出一种温暖的金黄色。即使是普通民居,也像是经过精心布置的电影场景。鲜花、绿植和爬藤沿着石墙自然生长,不需要太多装饰,便已经很有英国乡村的味道。

风景很美,行程却有些匆忙

科茨沃尔德适合慢慢游览。 理想的方式应该是在这里住上一两个晚上,上午去一个小镇散步,中午找家酒吧吃饭,下午沿着乡间小路走一走。累了便坐在河边喝咖啡,而不是不断查看时间,盘算还要开多久才能回到剑桥。 但我们这次显然不是这种节奏。 因为下午一点多才到,又想尽量多看几个地方,所以大部分时间都在“开车—停车—散步—拍照—再开车”之间切换。很多地方只是匆匆走过,刚刚觉得有点意思,就要准备前往下一个小镇了。 到了傍晚,我们不得不结束游览,开始漫长的返程。白天走路时还没有觉得特别累,真正坐进车里,想到前面还有几个小时的路程,才意识到这趟一日游确实安排得有些紧。 回到剑桥时已经很晚了。一天开了八个小时,真正游玩的时间只有几个小时,从时间利用率来看,似乎并不算划算。 但旅行有时候也不能只计算效率。

照片留下了那一天

一年以后再看这些照片,已经不太记得三个小镇分别叫什么,也记不清每一段路具体通向哪里。但仍然记得那天的阳光、河里的天鹅、树荫下的小路、古老的石头房屋,以及一家人在乡村酒吧里吃午饭的情景。 记忆会慢慢模糊,照片却把那一天零散地保存了下来。 科茨沃尔德的美并不是壮观或者震撼,而是一种缓慢、安静而又自然的美。这里没有特别高大的建筑,也没有必须打卡的宏伟景点,吸引人的恰恰是那些普通的河流、房屋、花园和乡间小路。 这次一日往返多少有些仓促,也留下了一点遗憾。下次再去科茨沃尔德,还是应该按照最初的计划,在那里住上一晚。 少赶几个小镇,少开几个小时的车,给自己更多时间坐在河边,看天鹅游过,看夕阳慢慢落在那些蜂蜜色的石头房子上。
下面按截图中图片的顺序,从左到右、从上到下编号,共 52 张: 第一排 在科茨沃尔德的乡村酒吧翻看午餐菜单。 长途驾驶后,先用两杯冰凉的啤酒稍作休息。 乡村酒吧里分量十足的英式午餐。 色彩丰富、摆盘精致的一道主菜。 简单而精致的乡村酒吧料理。 午餐桌上的清爽沙拉与时蔬。 从剑桥一路开往科茨沃尔德,漫长旅程仍在继续。 沿着绿篱环绕的小路,走进宁静的英国乡村。 树荫覆盖的乡间步道,为盛夏带来一丝清凉。 坐在户外餐桌旁享用午餐的孩子们。 长途旅行之后,终于可以安心吃饭了。 蜂蜜色石屋排列在古老的村庄街道两旁。 绿树掩映下,一条清澈的小河静静流过。 穿过树林与石屋之间的宁静乡间公路。 河边展示的科茨沃尔德乡村风景画。 蓝天白云下,古老石屋构成了典型的英伦乡村画面。 第二排 水鸟在清澈的河水中悠闲游动。 一家人坐在树荫下休息,享受难得的悠闲时光。 盛夏阳光下,科茨沃尔德乡村中的蓝裙倩影。 坐在乡村餐厅里,记录旅途中的轻松一刻。 漫步在安静的村庄街道上。 巨大的向日葵,为夏日旅程增添了明亮色彩。 古老石屋与乡村花园之间的夏日留影。 在户外茶座享用下午茶,感受英式乡村生活。 遮阳伞下的悠闲时光。 古老石墙和木门前的旅行留影。 蓝裙与蜂蜜色石屋,构成温柔的英伦夏日画面。 古老石窗与爬藤植物旁的乡村人像。 一组记录科茨沃尔德夏日之旅的照片。 安静坐落在路边的传统英式乡村住宅。 阳光透过茂密树冠,洒向林间小路。 绿树与灌木环绕的科茨沃尔德乡间公路。 第三排 白色小屋与蜂蜜色石墙相依而立。 游客穿行在古老而热闹的村庄街道上。 清澈的小河穿过茂密的树林。 绿意环绕的河流,静静倒映着岸边树木。 孩子们坐在河边长椅上休息。 乡村酒吧门前的黑板菜单与古老石墙。 石桥横跨温德拉什河,连接着水上伯顿的两岸。 水鸟在温德拉什河中悠闲觅食。 河水清澈见底,水鸟在浅滩间缓缓游动。 树影下的河面安静而幽深。 河中的水鸟与斑驳倒影。 阳光照在流动的河水上,泛起细碎波光。 水上伯顿模型村中的微缩石屋建筑。 盛开的向日葵,为旅程带来明亮的夏日气息。 The Cotswold Pottery 橱窗里陈列的手工陶器。 蜂蜜色石屋构成了科茨沃尔德最经典的村庄景色。 第四排 阳光下泛着金黄色光泽的树叶。 夏日的水上伯顿,河岸边坐满了游客。 绿树与藤蔓环绕的传统英式庄园住宅。 树荫深处的古老石屋,安静地守在水边。

---- 照片分割线 ---
[caption id="attachment_72167" align="alignnone" width="1024"]中午到了在小酒馆歇息/媳妇 中午到了在小酒馆歇息/媳妇[/caption] [caption id="attachment_72206" align="alignnone" width="2048"]河中的水鸟与斑驳倒影。 河中的水鸟与斑驳倒影。[/caption] [caption id="attachment_72205" align="alignnone" width="2048"]阳光照在流动的河水上,泛起细碎波光。 阳光照在流动的河水上,泛起细碎波光。[/caption] [caption id="attachment_72204" align="alignnone" width="2048"]水上伯顿模型村中的微缩石屋建筑。 水上伯顿模型村中的微缩石屋建筑。[/caption] [caption id="attachment_72203" align="alignnone" width="1365"]乡村酒吧门前的黑板菜单与古老石墙。 乡村酒吧门前的黑板菜单与古老石墙。[/caption] [caption id="attachment_72202" align="alignnone" width="2048"]娃走累了就坐在石头上歇会儿。 娃走累了就坐在石头上歇会儿。[/caption] [caption id="attachment_72201" align="alignnone" width="2048"]绿树与灌木环绕的科茨沃尔德乡间公路。 绿树与灌木环绕的科茨沃尔德乡间公路。[/caption] [caption id="attachment_72200" align="alignnone" width="2048"]阳光透过茂密树冠,洒向林间小路。 阳光透过茂密树冠,洒向林间小路。[/caption] [caption id="attachment_72199" align="alignnone" width="2048"]开了三个多小时终于到了小镇,在镇中心的小广场上。 开了三个多小时终于到了小镇,在镇中心的小广场上。[/caption] [caption id="attachment_72198" align="alignnone" width="2048"]蓝裙与蜂蜜色石屋,构成温柔的英伦夏日画面。 蓝裙与蜂蜜色石屋,构成温柔的英伦夏日画面。[/caption] [caption id="attachment_72197" align="alignnone" width="2048"]古老石墙和木门前的旅行留影。 古老石墙和木门前的旅行留影。[/caption] [caption id="attachment_72196" align="alignnone" width="2048"]小树林鸟儿叽叽喳喳 小树林鸟儿叽叽喳喳[/caption] [caption id="attachment_72195" align="alignnone" width="1001"]在户外茶座享用下午茶,感受英式乡村生活。在酒巴的后院里,吃着简易三明制 在户外茶座享用下午茶,感受英式乡村生活。在酒巴的后院里,吃着简易三明制[/caption] [caption id="attachment_72194" align="alignnone" width="1024"]古老石屋与乡村花园之间的夏日留影。 古老石屋与乡村花园之间的夏日留影。[/caption] [caption id="attachment_72193" align="alignnone" width="1024"]巨大的向日葵,为夏日旅程增添了明亮色彩。 巨大的向日葵,为夏日旅程增添了明亮色彩。[/caption] [caption id="attachment_72192" align="alignnone" width="1024"]漫步在安静的村庄街道上。 漫步在安静的村庄街道上。[/caption] [caption id="attachment_72191" align="alignnone" width="1024"]坐在乡村餐厅里,记录旅途中的轻松一刻。 坐在乡村餐厅里,记录旅途中的轻松一刻。[/caption] [caption id="attachment_72190" align="alignnone" width="1024"]盛夏阳光下,科茨沃尔德乡村中的蓝裙倩影。 盛夏阳光下,科茨沃尔德乡村中的蓝裙倩影。[/caption] [caption id="attachment_72189" align="alignnone" width="2048"]一家人坐在树荫下休息,享受难得的悠闲时光。 一家人坐在树荫下休息,享受难得的悠闲时光。[/caption] [caption id="attachment_72188" align="alignnone" width="2048"]水鸟/鸭子在清澈的河水中悠闲游动。 水鸟/鸭子在清澈的河水中悠闲游动。[/caption] [caption id="attachment_72187" align="alignnone" width="2048"]蓝天白云下,古老石屋构成了典型的英伦乡村画面。 蓝天白云下,古老石屋构成了典型的英伦乡村画面。[/caption] [caption id="attachment_72186" align="alignnone" width="2048"]河边展示的科茨沃尔德乡村风景画。 河边展示的科茨沃尔德乡村风景画。[/caption] [caption id="attachment_72185" align="alignnone" width="1365"]穿过树林与石屋之间的宁静乡间公路。 穿过树林与石屋之间的宁静乡间公路。[/caption] [caption id="attachment_72184" align="alignnone" width="2048"]绿树掩映下,一条清澈的小河静静流过。 绿树掩映下,一条清澈的小河静静流过。[/caption] [caption id="attachment_72183" align="alignnone" width="1365"]蜂蜜色石屋排列在古老的村庄街道两旁。 蜂蜜色石屋排列在古老的村庄街道两旁。[/caption] [caption id="attachment_72182" align="alignnone" width="1365"]长途旅行之后,终于可以安心吃饭了。 长途旅行之后,终于可以安心吃饭了。[/caption] [caption id="attachment_72181" align="alignnone" width="2048"]坐在户外餐桌旁享用午餐的孩子们。 坐在户外餐桌旁享用午餐的孩子们。[/caption] [caption id="attachment_72180" align="alignnone" width="2048"]树荫覆盖的乡间步道,为盛夏带来一丝清凉。 树荫覆盖的乡间步道,为盛夏带来一丝清凉。[/caption] [caption id="attachment_72179" align="alignnone" width="2048"]沿着绿篱环绕的小路,走进宁静的英国乡村。 沿着绿篱环绕的小路,走进宁静的英国乡村。[/caption] [caption id="attachment_72178" align="alignnone" width="2048"]从剑桥一路开往科茨沃尔德,漫长旅程仍在继续。开车8小时 338英理,刚到家,累死了 从剑桥一路开往科茨沃尔德,漫长旅程仍在继续。开车8小时 338英理,刚到家,累死了[/caption] [caption id="attachment_72177" align="alignnone" width="2048"]午餐桌上的清爽沙拉与时蔬。 午餐桌上的清爽沙拉与时蔬。[/caption] [caption id="attachment_72176" align="alignnone" width="2048"]简单而精致的乡村酒吧料理。 简单而精致的乡村酒吧料理。[/caption] [caption id="attachment_72175" align="alignnone" width="2048"]色彩丰富、摆盘精致的一道主菜。 色彩丰富、摆盘精致的一道主菜。[/caption] [caption id="attachment_72174" align="alignnone" width="2048"]乡村酒吧里分量十足的英式午餐。 乡村酒吧里分量十足的英式午餐。[/caption] [caption id="attachment_72173" align="alignnone" width="2048"]长途驾驶后,先用两杯冰凉的啤酒稍作休息。 长途驾驶后,先用两杯冰凉的啤酒稍作休息。[/caption] [caption id="attachment_72172" align="alignnone" width="864"]在科茨沃尔德的乡村酒吧翻看午餐菜单。 在科茨沃尔德的乡村酒吧翻看午餐菜单。[/caption] [caption id="attachment_72171" align="alignnone" width="1536"]媳妇朋友圈/九宫格/摄影 媳妇朋友圈/九宫格/摄影[/caption] [caption id="attachment_72170" align="alignnone" width="2048"]媳妇在小石屋前留影 媳妇在小石屋前留影[/caption] [caption id="attachment_72169" align="alignnone" width="1024"]古老石窗与爬藤植物旁的乡村人像。 古老石窗与爬藤植物旁的乡村人像。[/caption] [caption id="attachment_72168" align="alignnone" width="1024"]媳妇/古老石墙和木门前的旅行留影。 媳妇/古老石墙和木门前的旅行留影。[/caption] [caption id="attachment_72218" align="alignnone" width="2048"]树荫深处的古老石屋,安静地守在水边。 树荫深处的古老石屋,安静地守在水边。[/caption] [caption id="attachment_72217" align="alignnone" width="1365"]绿树与藤蔓环绕的传统英式庄园住宅。 绿树与藤蔓环绕的传统英式庄园住宅。[/caption] [caption id="attachment_72216" align="alignnone" width="2048"]树荫深处的古老石屋,安静地守在水边。 树荫深处的古老石屋,安静地守在水边。[/caption] [caption id="attachment_72215" align="alignnone" width="2048"]夏日的水上伯顿,河岸边坐满了游客。 夏日的水上伯顿,河岸边坐满了游客。[/caption] [caption id="attachment_72214" align="alignnone" width="1365"]阳光下泛着金黄色光泽的树叶。 阳光下泛着金黄色光泽的树叶。[/caption] [caption id="attachment_72213" align="alignnone" width="2048"]古老的小城镇 古老的小城镇[/caption] [caption id="attachment_72212" align="alignnone" width="1365"]Cotswold Pottery 科茨沃尔德陶器/街上看到的 The Cotswold Pottery 橱窗里陈列的手工陶器。 Cotswold Pottery 科茨沃尔德陶器/街上看到的 The Cotswold Pottery 橱窗里陈列的手工陶器。[/caption] [caption id="attachment_72211" align="alignnone" width="2048"]盛开的向日葵,为旅程带来明亮的夏日气息。 盛开的向日葵,为旅程带来明亮的夏日气息。[/caption] [caption id="attachment_72210" align="alignnone" width="2048"]小城镇上有名的 The Chestnut Tree 小城镇上有名的 The Chestnut Tree[/caption] [caption id="attachment_72209" align="alignnone" width="2048"]狗子很开心的玩水 狗子很开心的玩水[/caption] [caption id="attachment_72208" align="alignnone" width="2048"]河水清澈见底,水鸟在浅滩间缓缓游动。 河水清澈见底,水鸟在浅滩间缓缓游动。[/caption] [caption id="attachment_72207" align="alignnone" width="2048"]河里的天鹅 河里的天鹅[/caption] [show_posts keyword="旅游"]

一个人的生命力, 藏在他的欲望里

2026-07-21 23:44:43

一个人的生命力,往往藏在食欲、性欲、表达欲和分享欲之中。它们代表着我们是否还对生活保持兴趣,是否愿意感受快乐、记录经历、亲近他人。随着年龄增长,欲望会发生变化,但真正重要的并不是一味放纵,而是在节制与热情之间找到平衡。人生不过三万多天,不必人人都去改变世界;能够认真生活、陪伴家人、记录美好,并在年老时回望过去,觉得这一生值得,便已足够。

生命力的四要素: 性欲、食欲、表达欲望、分享欲 - 你还剩几个?

前几天看到一个视频,里面提到衡量一个人生命力的四种欲望:食欲、性欲、表达欲和分享欲。 仔细想想,似乎还真有几分道理。 这里所说的“欲望”,并不一定是贪婪或者放纵,而是一个人对生活是否依然有兴趣、有热情、有回应。一个人还愿意吃、愿意说、愿意分享、愿意亲近别人,至少说明他与这个世界之间仍然保持着连接。

食欲:最简单,也最难控制的快乐

四种欲望里,食欲大概是最容易得到满足的。 想吃什么,买来吃就是了。相比其他欲望,吃东西的门槛实在太低。最大的副作用,大概就是体重越来越高,裤腰越来越紧。 年轻的时候,我在吃这件事上几乎从来没有控制过,但人还是很瘦。我记得刚博士毕业时,体重也就一百三十斤左右。现在已经一百六十多斤了。粗略算下来,平均每年增加两斤,时间看起来没留下多少痕迹,体重倒是很诚实地记录了岁月。 直到最近开始减肥,我才真正体会到,“迈开腿”不容易,“管住嘴”其实更难。 明明已经吃饱了,看到喜欢的东西还是想尝一口;明明知道晚上不应该再吃,脑子里却总能找到一个理由:今天太累了,偶尔一次没关系,明天再开始。 以前听人说,一个人只要还能吃,身体通常就不会太差。虽然这句话未必完全科学,但食欲确实是身体状态和生活热情的一种表现。只是到了这个年纪,既要保留对美食的兴趣,也要学会适可而止。毕竟,真正长久的快乐,不是想吃什么就一直吃,而是身体还能允许自己偶尔放心地吃。 [caption id="attachment_72155" align="alignnone" width="860"]饿了好几周/才瘦了一点点,减肥好难啊。 饿了好几周/才瘦了一点点,减肥好难啊。[/caption]

表达欲和分享欲:给生活留下证据

表达欲和分享欲往往是连在一起的。 发朋友圈、写博客、拍视频、做UP主,本质上都是在记录和表达:我去了哪里,我看到了什么,我此刻有什么感受,我想把什么留给未来的自己。 我很喜欢记录生活,也喜欢分享。至于别人爱不爱看,我其实没有那么在意。朋友圈、博客和视频,对我来说更像是一份档案/日记本。现在记录下来,等老了以后再回头翻看,至少还能知道,自己曾经怎样生活过。 有时候晚上躺在床上,我会翻看很多年前发过的朋友圈。看到一张照片、一段视频,当时的地点、天气、声音和心情,常常会一下子重新浮现出来。 人的记忆其实并不可靠。很多当时以为永远不会忘记的事情,过几年以后就只剩下模糊的轮廓。但一张照片、一小段文字,往往能重新打开整段记忆。 我曾经有一次生病,那一周竟然连续五天没有发朋友圈。对我这样几乎每天都会记录的人来说,确实很反常。 我姐姐以前也说过,有时几天没有和我联系,她会特意看一下我的朋友圈。只要发现我还在正常更新,她就觉得我应该没什么事。 原来朋友圈不仅是在分享生活,有时候也像是在向关心自己的人报平安。

教家人,也是一种表达和分享

我平时喜欢教孩子,也喜欢给媳妇讲各种知识。仔细想想,这其实也是表达欲和分享欲的一部分。 学到一个新东西,弄明白一个道理,或者发现一种更好的方法,我就会忍不住想讲给身边的人听。知识只有留在自己脑子里,好像还不够完整;讲出来,分享出去,甚至帮助别人理解和使用,才算真正发挥了价值。 当然,教孩子除了满足自己的表达欲,也确实有很多实际好处。孩子多少总能学到一些东西。 至于教媳妇,她最后到底学会了多少,我有时也不太确定。不过她愿意听我讲,愿意配合,还提供了很多情绪价值,这本身就已经很难得了。 [caption id="attachment_72150" align="alignnone" width="1448"]教媳妇PowerBI - 可能得等到年老的时候才有时间来剪辑这个视频。 教媳妇PowerBI - 可能得等到年老的时候才有时间来剪辑这个视频。[/caption] 一个人愿意讲,另一个人愿意听,也是一种生活里的默契。

性欲:亲密关系里的生命信号

最后一个是性欲。谈到这个,大众大多会很羞涩。 年轻的时候精力充沛,欲望来得直接,一天好几次/也很少考虑太多。随着年龄增长,工作、家庭、经济、健康和各种责任接踵而来,人的身体和心理状态都会发生变化,欲望自然不可能永远停留在二十岁。 古人说“饱暖思淫欲”,虽然表达得有些直白,但也说明亲密欲望往往建立在基本生活相对稳定的基础上。当一个人长期疲惫、焦虑或者压力过大时,很难还有足够的精力去感受亲密关系带来的快乐。 而且,性欲和食欲不同。吃饭是一个人的事情,亲密关系却通常需要两个人的状态、意愿和情绪互相配合。它不只是生理冲动,也包括信任、陪伴、欣赏和被需要的感觉。 当然,欲望强弱并没有统一标准,也不能简单用次数衡量。真正重要的,是一个人是否还保留着感受亲密、欣赏美好和与他人建立连接的能力。 年轻的时候,我并没有特别觉得二十多岁的人有多好看。到了现在,反而越来越容易注意到年轻人身上的朝气。他们可能不需要精心打扮,脸上就有一种自然的明亮和鲜活。 或许真正让人羡慕的,并不只是年轻的外貌,而是那种尚未被生活磨损的生命状态。

人活着,总要对世界有一点兴趣

一个人是否年轻,不能只看身份证上的年龄,更要看他对生活是否仍然有欲望。 还想吃喜欢的东西,还愿意表达自己的想法,还想把快乐分享给别人,还能够感受亲密和美好,这些都说明一个人的内心还没有完全衰老。 当然,欲望也需要节制。食欲如果毫无控制,会损害健康;表达欲如果不顾场合,会变成自说自话;分享欲如果过度依赖别人的回应,也可能给自己增加焦虑;性欲如果失去边界,同样会带来麻烦。 真正的生命力,并不是被欲望牵着走,而是在欲望与理性之间保持平衡:既不麻木,也不过度放纵。 如果一个人对什么都没有兴趣,什么都不想做,什么都不愿意说,日子只是机械地重复,那么即使身体还年轻,精神也可能已经提前衰老。什么忘记都没有,人和咸鱼有什么区别? 人好不容易来到这个世界。人生看似漫长,算下来也不过三万多天,过去一天,就少一天。 我没有那么多宏伟的理想,也不再幻想自己一定要改变世界。到了这个年纪,我大概已经知道自己的能力边界在哪里,职业发展的天花板也逐渐看得清楚。承认这一点,并不一定是消极,而是开始把有限的时间放在真正重要的事情上。 好好吃饭,认真工作,陪伴家人,教孩子一些东西,记录值得记录的时刻,偶尔旅行,偶尔分享,也让自己多一些快乐。 等到有一天真的老了,再翻看过去的朋友圈、博客和视频,看到曾经去过的地方、陪伴过的人、做过的事情,能够对自己说一句: 这一生未必轰轰烈烈,但我认真活过,也得到过很多快乐。 这样,就已经很值得了。 [bctt tweet='借用一句不太严谨的“四大皆空”:希望我们对生活的这四种欲望,都晚一点消失。']

使用 Python 和 C++ 数值积分计算圆周率 Pi

2026-07-20 23:00:51

本文介绍如何利用定积分 [math]\pi=\int_0^1\frac{4}{1+x^2},dx[/math] 近似计算圆周率 Pi。文章先解释该积分为什么等于 Pi,然后介绍梯形法则和中点法则的数学原理,并给出 Python 与 C++ 的单线程、多线程实现。最后进一步说明如何将积分区间划分到五个分布式计算节点上,并比较不同实现方式的精度、性能、并行能力和适用场景。
[caption id="attachment_72138" align="alignnone" width="449"]定积分计算PI 定积分计算PI[/caption] 圆周率 Pi,通常写作 [math]\pi[/math],广泛出现在数学、物理、工程、统计学和计算机科学中。虽然大多数编程语言都已经提供了内置的 Pi 常量,但亲自计算 Pi 仍然是学习微积分、数值积分、多线程和分布式计算的一个很好的学习的例子。 本文将通过下面这个定积分计算 Pi: [math] \pi=\int_0^1\frac{4}{1+x^2}dx [/math] 本文将介绍:
  • 为什么这个积分等于 Pi
  • 数值积分如何近似计算定积分
  • 梯形法则
  • 中点法则
  • 单线程 Python 实现
  • 多线程 Python 实现
  • 单线程 C++ 实现
  • 多线程 C++ 实现
  • 如何将同一个算法分配到五个计算节点上

为什么这个积分等于 Pi?

考虑下面的定积分: [math] \int_0^1\frac{4}{1+x^2}dx [/math] 关键在于,反正切函数的导数是: [math] \frac{d}{dx}\arctan(x)=\frac{1}{1+x^2} [/math] 因此: [math] \int\frac{4}{1+x^2}dx=4\arctan(x)+C [/math] 将积分上下限零和一代入: [math] \int_0^1\frac{4}{1+x^2}dx=\left[4\arctan(x)\right]_0^1 [/math] 也就是: [math] \int_0^1\frac{4}{1+x^2}dx=4\arctan(1)-4\arctan(0) [/math] 我们知道: [math] \arctan(1)=\frac{\pi}{4} [/math] 并且: [math] \arctan(0)=0 [/math] 因此: [math] 4\left(\frac{\pi}{4}\right)-4(0)=\pi [/math] 所以: [math] \boxed{\pi=\int_0^1\frac{4}{1+x^2}dx} [/math] 这就为我们提供了一种通过数值积分计算 Pi 的方法。

数值积分是如何工作的?

计算机不一定要通过符号运算直接求出积分的解析解。它可以把积分区间分成许多很小的部分,然后近似计算曲线下面的面积。 假设我们需要计算: [math] I=\int_a^b f(x)dx [/math] 将区间 [math][a,b][/math] 分成 [math]N[/math] 个长度相等的小区间。 每个小区间的宽度为: [math] h=\frac{b-a}{N} [/math] 划分区间的各个点为: [math] x_i=a+ih [/math] 其中: [math] i=0,1,2,\ldots,N [/math] 近似计算每一个小区域的面积有多种方法。两种常见的方法是:
  • 梯形法则
  • 中点法则

梯形法则

你可能记得的那个包含 [math]f(0)[/math]、[math]f(1)[/math] 和除以二的公式,就是梯形法则。 对于从 [math]x_i[/math] 到 [math]x_{i+1}[/math] 的一个小区间,我们使用一条直线连接函数在两个端点上的值。 这样形成的区域是一个梯形。 它的面积近似为: [math] A_i\approx \frac{h}{2}(f(x_i)+f(x_{i+1})) [/math] 将所有梯形的面积相加,可以得到: [math] T_N= \frac{h}{2} \left[ f(x_0) +2f(x_1) +2f(x_2) +\cdots +2f(x_{N-1}) +f(x_N) \right] [/math] 一个等价并且通常更容易编程实现的公式是: [math] \boxed{ T_N= h\left[ \frac{f(a)+f(b)}{2} + \sum_{i=1}^{N-1}f(a+ih) \right] } [/math] 两个端点只计算一半的权重: [math] \frac{f(a)+f(b)}{2} [/math] 所有内部点使用完整权重: [math] f(a+h)+f(a+2h)+\cdots+f(b-h) [/math] 对于我们的 Pi 积分: [math] f(x)=\frac{4}{1+x^2} [/math] 并且: [math] a=0,\qquad b=1 [/math] 因此: [math] h=\frac{1}{N} [/math] 梯形法则对 Pi 的近似公式为: [math] \pi\approx h[\frac{f(0)+f(1)}{2}+\sum_{i=1}^{N-1}f(ih)] [/math] 因为: [math] f(0)=\frac{4}{1+0^2}=4 [/math] 并且: [math] f(1)=\frac{4}{1+1^2}=2 [/math] 所以还可以写成: [math] \pi\approx h[3+\sum_{i=1}^{N-1}\frac{4}{1+(ih)^2}] [/math]

一个简单的梯形法则示例

假设我们把积分区间分成四份: [math] N=4 [/math] 每个小区间的宽度为: [math] h=\frac{1}{4}=0.25 [/math] 五个边界点为: [math] 0,\quad0.25,\quad0.5,\quad0.75,\quad1 [/math] 函数在这些点上的值大约为: [math] f(0)=4 [/math] [math] f(0.25)\approx3.764706 [/math] [math] f(0.5)=3.2 [/math] [math] f(0.75)=2.56 [/math] [math] f(1)=2 [/math] 应用梯形法则: [math] T_4= 0.25\left[ \frac{4+2}{2} +3.764706+3.2+2.56 \right] [/math] 因此: [math] T_4\approx3.131176 [/math] Pi 的真实值大约为: [math] \pi\approx3.141593 [/math] 即使只划分为四个小区间,我们也已经得到了一个比较合理的近似值。增大 [math]N[/math] 可以进一步提高结果的精度。

中点法则

本文后面的主要代码使用的是中点法则。 梯形法则在每个小区间的边界上计算函数值,而中点法则在每个小区间的中心位置计算函数值。 第 [math]i[/math] 个区间的中点为: [math] x_i= a+\left(i+\frac{1}{2}\right)h [/math] 该小区间的面积可以近似看成一个矩形: [math] A_i\approx f(x_i)h [/math] 将所有矩形面积相加: [math] \boxed{ M_N= h\sum_{i=0}^{N-1} f\left( a+\left(i+\frac{1}{2}\right)h \right) } [/math] 对于 Pi 的积分,[math]a=0[/math]、[math]b=1[/math],并且 [math]h=1/N[/math]。 因此: [math] x_i=\left(i+\frac{1}{2}\right)h [/math] 并且: [math] \pi\approx h\sum_{i=0}^{N-1}\frac{4}{1+x_i^2} [/math] 代入 [math]h=1/N[/math]: [math] \boxed{ \pi\approx \frac{1}{N} \sum_{i=0}^{N-1} \frac{4}{ 1+ \left( \frac{i+\frac{1}{2}}{N} \right)^2 } } [/math] [math]N[/math] 越大,计算结果通常越接近 Pi 的真实值。

梯形法则与中点法则的比较

方法 函数取值位置 公式
梯形法则 每个区间的边界 [math]h\left[\frac{f(a)+f(b)}{2}+\sum_{i=1}^{N-1}f(a+ih)\right][/math]
中点法则 每个区间的中心 [math]h\sum_{i=0}^{N-1}f\left(a+\left(i+\frac12\right)h\right)[/math]
对于足够平滑的函数,这两种方法的误差通常都与下面的量成正比: [math] \frac{1}{N^2} [/math] 不过,在使用相同数量小区间的情况下,中点法则通常比梯形法则更加精确。

使用中点法则的单线程 Python 实现

下面的 Python 程序将积分区间划分成 2500 万个小区间。
import math
import time


def calculate_pi(total_steps: int) -> float:
    if total_steps <= 0:
        raise ValueError("total_steps 必须为正数")

    step_width = 1.0 / total_steps
    total = 0.0

    for step in range(total_steps):
        midpoint = (step + 0.5) * step_width
        total += 4.0 / (1.0 + midpoint * midpoint)

    return total * step_width


def main() -> None:
    total_steps = 25_000_000

    started_at = time.perf_counter()
    pi_estimate = calculate_pi(total_steps)
    elapsed_seconds = time.perf_counter() - started_at

    absolute_error = abs(pi_estimate - math.pi)

    print(f"Pi 估算值:    {pi_estimate:.15f}")
    print(f"Pi 参考值:    {math.pi:.15f}")
    print(f"绝对误差:     {absolute_error:.3e}")
    print(f"运行时间:     {elapsed_seconds:.3f} 秒")


if __name__ == "__main__":
    main()
核心计算代码是:
midpoint = (step + 0.5) * step_width
total += 4.0 / (1.0 + midpoint * midpoint)
第一行计算当前小区间的中点: [math] x_i=\left(i+\frac12\right)h [/math] 第二行计算函数值: [math] f(x_i)=\frac{4}{1+x_i^2} [/math] 在累加所有函数值之后,再乘以每个小区间的宽度:
return total * step_width
这在数学上对应: [math] h\sum_{i=0}^{N-1}f(x_i) [/math]

使用梯形法则的单线程 Python 实现

梯形法则版本在各个小区间的边界位置计算函数值,而不是在中点计算。
import math
import time


def calculate_pi_trapezoidal(total_steps: int) -> float:
    if total_steps <= 0:
        raise ValueError("total_steps 必须为正数")

    h = 1.0 / total_steps

    def f(x: float) -> float:
        return 4.0 / (1.0 + x * x)

    total = 0.5 * (f(0.0) + f(1.0))

    for step in range(1, total_steps):
        x = step * h
        total += f(x)

    return total * h


def main() -> None:
    total_steps = 25_000_000

    started_at = time.perf_counter()
    pi_estimate = calculate_pi_trapezoidal(total_steps)
    elapsed_seconds = time.perf_counter() - started_at

    absolute_error = abs(pi_estimate - math.pi)

    print(f"Pi 估算值:    {pi_estimate:.15f}")
    print(f"Pi 参考值:    {math.pi:.15f}")
    print(f"绝对误差:     {absolute_error:.3e}")
    print(f"运行时间:     {elapsed_seconds:.3f} 秒")


if __name__ == "__main__":
    main()
两个端点的贡献通过下面的代码计算:
total = 0.5 * (f(0.0) + f(1.0))
这对应: [math] \frac{f(0)+f(1)}{2} [/math] 循环计算所有内部点的函数值之和:
for step in range(1, total_steps):
    x = step * h
    total += f(x)
这对应: [math] \sum_{i=1}^{N-1}f(ih) [/math] 最后再乘以 [math]h[/math]:
return total * h

使用中点法则的多线程 Python 实现

我们可以把 2500 万个小区间分配给五个工作线程。 对于总共 [math]P[/math] 个工作线程中的第 [math]r[/math] 个工作线程,它的起始位置为: [math] \text{start}_r= \left\lfloor \frac{Nr}{P} \right\rfloor [/math] 结束位置为: [math] \text{end}_r= \left\lfloor \frac{N(r+1)}{P} \right\rfloor [/math] 对于五个工作线程和 2500 万个小区间:
工作线程 起始步骤 结束步骤 步骤数量
0 0 5,000,000 5,000,000
1 5,000,000 10,000,000 5,000,000
2 10,000,000 15,000,000 5,000,000
3 15,000,000 20,000,000 5,000,000
4 20,000,000 25,000,000 5,000,000
下面使用 ThreadPoolExecutor 实现:
import math
import time
from concurrent.futures import ThreadPoolExecutor


def calculate_partial_sum(
    start_step: int,
    end_step: int,
    step_width: float,
) -> float:
    partial_sum = 0.0

    for step in range(start_step, end_step):
        midpoint = (step + 0.5) * step_width
        partial_sum += 4.0 / (1.0 + midpoint * midpoint)

    return partial_sum


def calculate_pi_multithreaded(
    total_steps: int,
    worker_count: int,
) -> float:
    if total_steps <= 0:
        raise ValueError("total_steps 必须为正数")

    if worker_count <= 0:
        raise ValueError("worker_count 必须为正数")

    step_width = 1.0 / total_steps
    ranges = []

    for worker_id in range(worker_count):
        start_step = total_steps * worker_id // worker_count
        end_step = total_steps * (worker_id + 1) // worker_count
        ranges.append((start_step, end_step))

    with ThreadPoolExecutor(max_workers=worker_count) as executor:
        futures = [
            executor.submit(
                calculate_partial_sum,
                start_step,
                end_step,
                step_width,
            )
            for start_step, end_step in ranges
        ]

        partial_sums = [
            future.result()
            for future in futures
        ]

    return sum(partial_sums) * step_width


def main() -> None:
    total_steps = 25_000_000
    worker_count = 5

    started_at = time.perf_counter()

    pi_estimate = calculate_pi_multithreaded(
        total_steps,
        worker_count,
    )

    elapsed_seconds = time.perf_counter() - started_at
    absolute_error = abs(pi_estimate - math.pi)

    print(f"工作线程数:   {worker_count}")
    print(f"Pi 估算值:    {pi_estimate:.15f}")
    print(f"Pi 参考值:    {math.pi:.15f}")
    print(f"绝对误差:     {absolute_error:.3e}")
    print(f"运行时间:     {elapsed_seconds:.3f} 秒")


if __name__ == "__main__":
    main()
每个工作线程计算一个部分和: [math] S_r= \sum_{i=\text{start}_r}^{\text{end}_r-1} \frac{4}{1+x_i^2} [/math] 主线程再把这些结果合并起来: [math] \pi\approx h(S_0+S_1+S_2+S_3+S_4) [/math]

Python 多线程的一个重要限制

这个多线程 Python 版本展示了如何把计算划分为多个独立区间,但它不一定比单线程版本运行得更快。 标准 CPython 存在全局解释器锁,也就是通常所说的 GIL。 对于 CPU 密集型 Python 代码,在同一时刻通常只有一个线程能够执行 Python 字节码。 因此,五个 Python 线程并不意味着能够有效地同时使用五个 CPU 核心。 这个多线程版本可能会出现以下情况:
  • 运行速度与单线程版本基本相同
  • 由于线程管理开销,运行速度反而稍慢
  • 适合演示如何分配计算任务
  • 不适合在普通 CPython 中实现真正的 CPU 并行计算
如果需要在 Python 中实现真正的 CPU 并行,可以考虑:
  • ProcessPoolExecutor
  • multiprocessing 模块
  • NumPy
  • 本地编译扩展
  • MPI
  • 独立的分布式进程

使用中点法则的单线程 C++ 实现

C++ 非常适合执行这种紧密的数值循环,因为它可以被编译为本地机器代码/Native Code。
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <stdexcept>


double calculate_pi(std::uint64_t total_steps) {
    if (total_steps == 0) {
        throw std::invalid_argument(
            "total_steps 必须为正数"
        );
    }

    const double step_width =
        1.0 / static_cast<double>(total_steps);

    double total = 0.0;

    for (
        std::uint64_t step = 0;
        step < total_steps;
        ++step
    ) {
        const double midpoint =
            (static_cast<double>(step) + 0.5)
            * step_width;

        total += 4.0 / (1.0 + midpoint * midpoint);
    }

    return total * step_width;
}


int main() {
    constexpr std::uint64_t total_steps = 25'000'000;

    const auto started_at =
        std::chrono::steady_clock::now();

    const double pi_estimate =
        calculate_pi(total_steps);

    const auto finished_at =
        std::chrono::steady_clock::now();

    const double elapsed_seconds =
        std::chrono::duration<double>(
            finished_at - started_at
        ).count();

    const double reference_pi = std::acos(-1.0);

    const double absolute_error =
        std::abs(pi_estimate - reference_pi);

    std::cout
        << std::fixed
        << std::setprecision(15);

    std::cout
        << "Pi 估算值:    "
        << pi_estimate
        << '\n';

    std::cout
        << "Pi 参考值:    "
        << reference_pi
        << '\n';

    std::cout
        << std::scientific
        << std::setprecision(3);

    std::cout
        << "绝对误差:     "
        << absolute_error
        << '\n';

    std::cout
        << std::fixed
        << std::setprecision(3);

    std::cout
        << "运行时间:     "
        << elapsed_seconds
        << " 秒\n";

    return 0;
}
使用优化选项进行编译:
g++ -O3 -std=c++17 pi_single.cpp -o pi_single
运行程序:
./pi_single
-O3 选项会启用较为激进的编译器优化。如果不启用优化,程序的运行速度可能会慢很多。

使用梯形法则的单线程 C++ 实现

下面的 C++ 程序实现了梯形法则: [math] T_N= h\left[ \frac{f(0)+f(1)}{2} + \sum_{i=1}^{N-1}f(ih) \right] [/math]
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <stdexcept>


double f(double x) {
    return 4.0 / (1.0 + x * x);
}


double calculate_pi_trapezoidal(
    std::uint64_t total_steps
) {
    if (total_steps == 0) {
        throw std::invalid_argument(
            "total_steps 必须为正数"
        );
    }

    const double h =
        1.0 / static_cast<double>(total_steps);

    double total =
        0.5 * (f(0.0) + f(1.0));

    for (
        std::uint64_t step = 1;
        step < total_steps;
        ++step
    ) {
        const double x =
            static_cast<double>(step) * h;

        total += f(x);
    }

    return total * h;
}


int main() {
    constexpr std::uint64_t total_steps = 25'000'000;

    const auto started_at =
        std::chrono::steady_clock::now();

    const double pi_estimate =
        calculate_pi_trapezoidal(total_steps);

    const auto finished_at =
        std::chrono::steady_clock::now();

    const double elapsed_seconds =
        std::chrono::duration<double>(
            finished_at - started_at
        ).count();

    const double reference_pi = std::acos(-1.0);

    const double absolute_error =
        std::abs(pi_estimate - reference_pi);

    std::cout
        << std::fixed
        << std::setprecision(15);

    std::cout
        << "Pi 估算值:    "
        << pi_estimate
        << '\n';

    std::cout
        << "Pi 参考值:    "
        << reference_pi
        << '\n';

    std::cout
        << std::scientific
        << std::setprecision(3);

    std::cout
        << "绝对误差:     "
        << absolute_error
        << '\n';

    std::cout
        << std::fixed
        << std::setprecision(3);

    std::cout
        << "运行时间:     "
        << elapsed_seconds
        << " 秒\n";

    return 0;
}
使用下面的命令编译:
g++ -O3 -std=c++17 pi_trapezoidal.cpp -o pi_trapezoidal

使用中点法则的多线程 C++ 实现

与普通 CPython 线程不同,C++ 线程可以在多个 CPU 核心上同时执行 CPU 密集型计算。 下面的实现将计算任务分配给五个线程。
#include <chrono>
#include <cmath>
#include <cstdint>
#include <iomanip>
#include <iostream>
#include <numeric>
#include <stdexcept>
#include <thread>
#include <vector>


double calculate_partial_sum(
    std::uint64_t start_step,
    std::uint64_t end_step,
    double step_width
) {
    double partial_sum = 0.0;

    for (
        std::uint64_t step = start_step;
        step < end_step;
        ++step
    ) {
        const double midpoint =
            (static_cast<double>(step) + 0.5)
            * step_width;

        partial_sum +=
            4.0 / (1.0 + midpoint * midpoint);
    }

    return partial_sum;
}


double calculate_pi_multithreaded(
    std::uint64_t total_steps,
    std::size_t worker_count
) {
    if (total_steps == 0) {
        throw std::invalid_argument(
            "total_steps 必须为正数"
        );
    }

    if (worker_count == 0) {
        throw std::invalid_argument(
            "worker_count 必须为正数"
        );
    }

    const double step_width =
        1.0 / static_cast<double>(total_steps);

    std::vector<std::thread> workers;

    std::vector<double> partial_sums(
        worker_count,
        0.0
    );

    workers.reserve(worker_count);

    for (
        std::size_t worker_id = 0;
        worker_id < worker_count;
        ++worker_id
    ) {
        const std::uint64_t start_step =
            total_steps
            * worker_id
            / worker_count;

        const std::uint64_t end_step =
            total_steps
            * (worker_id + 1)
            / worker_count;

        workers.emplace_back(
            [
                &,
                worker_id,
                start_step,
                end_step
            ]() {
                partial_sums[worker_id] =
                    calculate_partial_sum(
                        start_step,
                        end_step,
                        step_width
                    );
            }
        );
    }

    for (std::thread& worker : workers) {
        worker.join();
    }

    const double combined_sum =
        std::accumulate(
            partial_sums.begin(),
            partial_sums.end(),
            0.0
        );

    return combined_sum * step_width;
}


int main() {
    constexpr std::uint64_t total_steps = 25'000'000;
    constexpr std::size_t worker_count = 5;

    const auto started_at =
        std::chrono::steady_clock::now();

    const double pi_estimate =
        calculate_pi_multithreaded(
            total_steps,
            worker_count
        );

    const auto finished_at =
        std::chrono::steady_clock::now();

    const double elapsed_seconds =
        std::chrono::duration<double>(
            finished_at - started_at
        ).count();

    const double reference_pi = std::acos(-1.0);

    const double absolute_error =
        std::abs(pi_estimate - reference_pi);

    std::cout
        << "工作线程数:   "
        << worker_count
        << '\n';

    std::cout
        << std::fixed
        << std::setprecision(15);

    std::cout
        << "Pi 估算值:    "
        << pi_estimate
        << '\n';

    std::cout
        << "Pi 参考值:    "
        << reference_pi
        << '\n';

    std::cout
        << std::scientific
        << std::setprecision(3);

    std::cout
        << "绝对误差:     "
        << absolute_error
        << '\n';

    std::cout
        << std::fixed
        << std::setprecision(3);

    std::cout
        << "运行时间:     "
        << elapsed_seconds
        << " 秒\n";

    return 0;
}
使用线程支持和优化选项进行编译:
g++ -O3 -std=c++17 -pthread pi_multithreaded.cpp -o pi_multithreaded
运行程序:
./pi_multithreaded

为什么每个线程都使用自己的局部求和变量?

每个线程内部首先使用一个局部变量进行计算:
double partial_sum = 0.0;
线程不会在每一次循环中都修改同一个共享的全局变量。 如果所有线程不断更新同一个共享变量,程序就需要使用互斥锁或者原子操作。 这会引入同步开销和线程竞争,可能抵消多线程带来的性能优势。 因此,程序采用了类似 MapReduce 的模式:
  1. 为每个工作线程分配一段积分区间。
  2. 让每个工作线程独立完成计算。
  3. 每个线程保存一个部分结果。
  4. 等待所有线程结束。
  5. 将所有部分结果相加。
在数学上: [math] S=S_0+S_1+\cdots+S_{P-1} [/math] 最终近似值为: [math] \pi\approx Sh [/math]

将算法扩展到五个分布式计算节点

多线程和分布式计算使用相同的数学划分方法,但它们是两种不同的执行模型。 线程通常具有以下特点:
  • 运行在同一台机器上
  • 共享相同的内存空间
  • 属于同一个进程
  • 通过共享变量进行通信
分布式工作进程通常具有以下特点:
  • 作为独立进程运行
  • 可能运行在不同的物理机器上
  • 不共享普通的进程内存
  • 通过文件、Socket、MPI、RPC 或其他分布式运行时进行通信
在一个五节点任务中,每个进程都会获得一个 Rank: [math] r\in{0,1,2,3,4} [/math] 进程总数为: [math] P=5 [/math] 每个 Rank 使用下面的公式计算自己的任务起始位置: [math] \text{start}_r= \left\lfloor \frac{Nr}{P} \right\rfloor [/math] 结束位置为: [math] \text{end}_r= \left\lfloor \frac{N(r+1)}{P} \right\rfloor [/math] 在 Python 中,可以这样分配计算范围:
import os


rank = int(os.environ["RANK"])
world_size = int(os.environ["WORLD_SIZE"])

start_step = total_steps * rank // world_size
end_step = total_steps * (rank + 1) // world_size
每个 Rank 只计算自己负责的区间:
partial_sum = 0.0

for step in range(start_step, end_step):
    midpoint = (step + 0.5) * step_width

    partial_sum += 4.0 / (
        1.0 + midpoint * midpoint
    )
对于五个 Rank,最终结果为: [math] \pi\approx h(S_0+S_1+S_2+S_3+S_4) [/math] 在前面的 Singularity 示例中,每个 Rank 都会写入一个结果文件:
rank-0.json
rank-1.json
rank-2.json
rank-3.json
rank-4.json
Rank 0 等待全部五个文件生成,然后读取每个文件中的部分和,将它们相加,最终得到 Pi 的估算值。 这个过程实现了三种分布式操作:
  • 屏障同步(Barrier):等待所有工作节点完成计算
  • 收集(Gather):收集所有节点的部分结果
  • 归约(Reduce):将所有部分和相加
基于文件的实现比较简单,也很容易理解,但它假设所有节点都可以访问同一个共享输出目录。 在正式的生产级分布式程序中,通常会使用 MPI 或其他支持集合通信的框架,以获得更加可靠和高效的通信机制。

数值积分方法的精度

对于足够平滑的函数,梯形法则和中点法则的误差通常都与下面的量成正比: [math] \frac{1}{N^2} [/math] 这意味着,当小区间数量加倍时,数值积分误差可能大约缩小为原来的四分之一。 不过,无限增大 [math]N[/math] 并不意味着可以获得无限精度。 计算机使用有限精度的浮点数存储数据。当程序累加几百万甚至几十亿个数值时,舍入误差也可能逐渐累积。 并行版本和单线程版本在最后几位数字上也可能略有不同,因为浮点数加法并不严格满足结合律: [math] (a+b)+c\neq a+(b+c) [/math] 这些表达式在数学上是等价的,但是在有限精度浮点计算中,改变加法顺序可能会改变最终的舍入结果。

性能方面的注意事项

在以下条件下,多线程 C++ 实现通常会比单线程版本更快:
  • 计算机拥有多个 CPU 核心
  • 计算任务足够大
  • 工作线程数量设置合理
  • 启用了编译器优化
使用五个线程并不保证一定能够获得五倍性能提升。 程序性能还会受到以下因素影响:
  • CPU 核心数量
  • 处理器运行频率
  • CPU 温度以及降频
  • 操作系统的线程调度
  • CPU 缓存行为
  • 线程创建和销毁开销
  • 计算机上正在运行的其他任务
对于 Python,GIL 是主要限制。增加 Python 线程数量通常无法加速纯 Python 的 CPU 密集型循环。 对于分布式计算,节点分配、进程启动、共享存储访问以及结果合并也都会产生额外开销。 使用 2500 万个区间计算 Pi 是一个很好的教学示例,但在真实生产环境中,这个计算任务过于简单,不值得为此分配多个昂贵的 GPU 计算节点。

不同实现方式的比较

实现方式 执行模型 真正的 CPU 并行 预期性能
Python 单线程 一个 Python 线程 实现简单,但速度相对较慢
Python 多线程 多个 Python 线程 通常不能,因为受到 GIL 限制 通常不会比单线程更快
C++ 单线程 一个本地线程 通常比纯 Python 快很多
C++ 多线程 多个本地线程 通常是本地计算中最快的版本
五节点分布式计算 多个独立工作进程 可以扩展,但存在启动和通信开销

总结

下面这个恒等式: [math] \pi=\int_0^1\frac{4}{1+x^2},dx [/math] 为我们提供了一个简单的例子,展示如何把微积分问题转换成计算机可以执行的数值计算问题。 梯形法则使用相邻边界点之间的直线近似曲线: [math] T_N= h\left[ \frac{f(a)+f(b)}{2} + \sum_{i=1}^{N-1}f(a+ih) \right] [/math] 中点法则使用每个小区间的中心位置计算函数值: [math] M_N= h\sum_{i=0}^{N-1} f\left( a+\left(i+\frac12\right)h \right) [/math] 同一个数学计算可以通过多种方式执行:
  • 在一个 CPU 核心上运行单个循环
  • 在同一台机器上使用多个线程
  • 使用多个进程和多个 CPU 核心
  • 使用运行在不同计算节点上的分布式工作进程
无论使用哪一种执行模型,背后的数学算法基本不变。 真正发生变化的是:如何划分积分区间、在哪里计算部分和,以及如何将所有部分结果重新合并起来。 这也是很多并行算法背后的核心模式:
任务分割 ---> 计算部分结果 ---> 合并计算最终结果
[math] \boxed{ \text{Tasks Partition} \rightarrow \text{Partial Computed Result} \rightarrow \text{Merged Final Result} } [/math] 虽然计算 Pi 只是一个简单的示例,但同样的 MapReduce 思想广泛应用于科学模拟、机器学习、数据处理、图形渲染、金融建模和大规模分布式系统中。 [show_file file="/var/www/wp-post-common/justyy.com/math.php"] 英文:Calculating Pi with Numerical Integration in Python and C [show_posts keyword="数学"]

月光奏鸣曲: 从学校礼堂弹到根特街头

2026-07-18 23:01:35

弟弟Ryan学钢琴曲一直很快。他的钢琴老师说,一般的新曲子,他大约两个星期就能学下来。不过,他有一个很明显的特点:只愿意认真弹自己喜欢的曲子。如果一首曲子没有打动他,想让他反复练习并不容易;但只要遇到真正喜欢的作品,他便会主动坐到钢琴前,一遍又一遍地弹。 贝多芬的《第十四钢琴奏鸣曲》,也就是大家熟悉的《月光奏鸣曲》,正好是他很喜欢的一首。 Ryan以前在小学的Assembly上表演过几次钢琴。对小学生来说,能够独自站在全校师生面前演奏,本身就需要不少勇气。更让他的同学们羡慕的是,他弹琴时通常不需要看谱,坐下来便可以直接开始演奏。因此,不少同学都觉得他弹琴特别厉害,对他很是崇拜。 当然,他的演奏也不是没有问题。 最明显的一点,就是弹得有些快。我在YouTube上听过一些《月光奏鸣曲》的完整演奏,很多版本大约需要十四分钟,而Ryan只用了十一分多钟就弹完了。速度快,听起来会更加紧凑,也更有冲击力,但这首作品并不只是对技巧和速度的考验,尤其是第一乐章,还需要足够的呼吸、层次和情绪控制。 对于孩子来说,能够完整地弹下来已经很不容易;但如果想继续向更高水平发展,下一步便不能只追求“弹得下来”,而是要学会控制节奏,理解不同乐章的性格,并把音乐中的情绪真正表达出来。 这首曲子也给我们留下过一段很特别的旅行记忆。 有一次全家去比利时旅行,我们来到根特市中心。那里恰好有一架可以演奏的钢琴,Ryan坐下来后,直接弹起了贝多芬的《月光奏鸣曲》。 琴声在市中心响起后,很快吸引了一些路人。有人停下脚步安静地听,也有人拿出手机拍照和录像。原本只是旅途中一次随兴的演奏,慢慢变成了一场小小的街头音乐会。 他连续弹了十一分多钟,我就在旁边一直举着相机录像。等他终于弹完,我的手臂都已经有些酸了。别人看到的是一个孩子在异国城市里从容地演奏,而我在镜头后面最直接的感受却是:这首曲子怎么还没有弹完?举相机也是一项体力活啊!想到这里,还是忍不住笑了出来。 整段演奏中,我最喜欢的是视频大约5分15秒以后进入的第三乐章。 如果说第一乐章像安静月光下的沉思,那么第三乐章则完全换了一种性格:急促、激烈,充满力量。音符不断向前推进,对手指速度、力度控制和整体稳定性都有很高的要求。Ryan自己也很喜欢这一部分,弹起来明显更加投入。 据说《月光奏鸣曲》也是他以后准备Diploma级别考试时可能涉及的曲目之一。现在的演奏当然还有不少可以改进的地方,例如速度需要更加克制,细节和情绪还可以继续打磨。不过,能够在这个年龄完整背谱演奏,并且愿意在学校礼堂和陌生城市的街头主动分享音乐,已经是一件值得记录的事情。 学钢琴并不只是为了通过考试,也不只是为了拿到某个等级证书。 真正珍贵的,是孩子能够遇到自己喜欢的音乐,并愿意投入时间,把它练下来、记在心里,最后在某个意想不到的地方演奏给别人听。 多年以后,我们可能不会记得他当时到底弹快了多少,也不会太在意那次演奏究竟是否完美。但我们大概会记得,在比利时根特的市中心,一个孩子坐在钢琴前,连续弹了十一分钟的贝多芬;路人停下来拍照,而我站在旁边举着相机,累得手臂发酸,却又舍不得错过任何一个画面。 视频:油管/Youtube | B站/小破站 | 微博视频 | 公众号视频 | 西瓜视频 | 微信视频号 | X/推特 | 小红书 | Facebook 视频:油管/Youtube | B站/小破站 | 微博视频 | 西瓜视频 | 微信视频号 | X/推特 | 小红书 | Facebook 视频:油管/Youtube | B站/小破站 | 微博视频 | 西瓜视频 | 微信视频号 | X/推特 | 小红书 | Facebook [show_file file="/var/www/wp-post-common/justyy.com/kid-learn-music.php"]

假期里的乐团时光: 孩子们参加 Holiday Orchestra 的一次经历

2026-07-16 22:53:29

前几年孩子们还小的时候,我们常利用假期给他们安排一些有意义的活动,Holiday Orchestra 就是其中之一。孩子们在几天时间里参加集中排练,学习与不同乐器和声部配合,并在最后一天登台演出。2023年12月30日,大娃作为大提琴手、二娃作为小提琴手,在剑桥 West Road Concert Hall 参加了这场音乐会。相比最终的演出,我更看重孩子们在排练过程中获得的参与感、责任感和团队协作经验。
[caption id="attachment_72115" align="alignnone" width="1279"]乐团表演节目单 乐团表演节目单[/caption] 前几年,孩子们还小的时候,每逢学校放假,我们通常都会给他们安排一些活动。一方面是不希望他们整个假期都待在家里,另一方面也想让他们接触一些课堂之外的体验。Holiday Orchestra 就是我们当时比较喜欢的一项活动。 Holiday Orchestra 是面向青少年音乐学习者组织的假期乐团活动,通常会根据孩子的年龄、演奏水平和所学乐器,把他们分到不同的乐团中。活动一般持续几天,孩子们每天到现场参加排练,在老师和指挥的带领下学习新的曲目,与其他乐手一起磨合,最后一天再举行一场正式演出,向家长展示这几天的排练成果。 我一直很喜欢这种形式。首先,它能让孩子们在假期里有事情做,而不是每天无所事事地待在家里。更重要的是,参加乐团和独自练琴完全不同。一个人在家练习时,只需要关注自己的音准、节奏和技巧;进入乐团之后,还要学会听指挥、跟随节拍、配合其他声部,并且知道什么时候应该突出,什么时候应该收敛。 这种经历可以让孩子真正体会到团队协作。一个人的演奏再出色,如果不能与其他乐手配合,也很难完成一场好的乐团表演。每个声部看起来只是整体中的一小部分,但所有乐器组合在一起,才能形成完整而丰富的音乐。 2023年12月30日,Holiday Orchestra 的结业演出在剑桥 West Road 的 The University Concert Hall 举行,地址是 11 West Road, Cambridge CB3 9DP。那一次,大娃参加的是大提琴声部,二娃参加的是小提琴声部。两个孩子学习的乐器不同,在乐团中的位置和作用也不一样,但都需要在短短几天内熟悉曲目,并与其他孩子完成合奏。 孩子们在小学阶段也参加过类似的学校乐团。一般来说,学习小提琴的孩子比较多,而学习大提琴的孩子相对少一些。大提琴体积大,携带起来不方便,价格通常也更高,可能正因为如此,在学校乐团里,大提琴手往往没有小提琴手那么多。 钢琴则是另一种情况。学习钢琴的孩子很多,但传统管弦乐团通常并不需要很多钢琴手,有些曲目甚至完全没有钢琴声部。即使需要,往往也只安排一位,因此竞争会比较激烈。相比之下,小提琴、大提琴、木管和铜管乐器在乐团中都有比较固定的声部和位置,也更容易让孩子获得长期参与合奏的机会。

《舞会佳人》与柴可夫斯基《第四交响曲》第三、四乐章|Holiday Orchestra 圣诞音乐会

那场音乐会上,乐团首先演奏了美国作曲家 Leroy Anderson 的《Belle of the Ball》。这是一首轻快、优雅而富有舞会气氛的作品,旋律活泼,很适合作为音乐会的开场。随后,乐团演奏了柴可夫斯基《F小调第四交响曲,作品36》的第三乐章和第四乐章。 第三乐章以弦乐拨弦为主要特色,声音轻巧而灵动;第四乐章则完全换了一种气氛,音乐突然变得宏大、热烈而充满力量。对于一个由青少年组成、只经过几天集中排练的乐团来说,这些曲目并不简单。孩子们能够把整场演出完成下来,本身就是一次很有意义的经历。 现在回头看,参加 Holiday Orchestra 的意义并不仅仅是最后那场演出。真正重要的是排练的过程:孩子们需要准时到场,需要耐心地反复练习,也需要接受自己只是整个乐团中的一员。他们可能不会记得每一个音符,也未必会一直学习同一种乐器,但这种与别人一起完成一件事情的经历,会成为成长过程中的一部分。 对家长来说,看到孩子们坐在舞台上,认真地看着指挥,和身边的乐手一起演奏,也是一件很欣慰的事情。几天的排练最终变成二十多分钟的演出,看起来时间不长,但其中包含了每个孩子的练习、配合和努力。 假期活动不一定非要以学习知识或者提高成绩为目标。有时候,让孩子参与一个团队,完成一次排练,登上一次舞台,本身就是很好的成长。 视频:油管/Youtube | B站/小破站 | 微博视频 | 公众号视频 | 西瓜视频 | 微信视频号 | X/推特 | 小红书 | Facebook [show_file file="/var/www/wp-post-common/justyy.com/kid-learn-music.php"] [show_posts keyword="音乐"] 英文:Holiday Orchestra Christmas Concert | Belle of the Ball & Tchaikovsky Symphony No. 4 | Holiday Orchestra Christmas Concert | Belle of the Ball & Tchaikovsky Symphony No. 4 [caption id="attachment_64193" align="alignnone" width="2048"]弟弟小提琴 弟弟小提琴[/caption] [caption id="attachment_64201" align="alignnone" width="1365"]老大大提琴 很帅气 老大大提琴 很帅气[/caption] [caption id="attachment_64200" align="alignnone" width="2048"]表演玩兄弟们在交流啥 表演玩兄弟们在交流啥[/caption] [caption id="attachment_64199" align="alignnone" width="1365"]老大第二乐器是大提琴 老大第二乐器是大提琴[/caption] [caption id="attachment_64198" align="alignnone" width="2048"]老二第二乐器是小提琴 老二第二乐器是小提琴[/caption] [caption id="attachment_64197" align="alignnone" width="1365"]老二第二乐器是小提琴 老二第二乐器是小提琴[/caption] [caption id="attachment_64196" align="alignnone" width="2048"]老二第二乐器是小提琴 老二第二乐器是小提琴[/caption]