mirror of
https://github.com/LCTT/TranslateProject.git
synced 2024-12-26 21:30:55 +08:00
Merge remote-tracking branch 'LCTT/master'
This commit is contained in:
commit
095c8b665d
@ -1,24 +1,24 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (geekpi)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10999-1.html)
|
||||
[#]: subject: (Installing alternative versions of RPMs in Fedora)
|
||||
[#]: via: (https://fedoramagazine.org/installing-alternative-rpm-versions-in-fedora/)
|
||||
[#]: author: (Adam Šamalík https://fedoramagazine.org/author/asamalik/)
|
||||
|
||||
在 Fedora 中安装替代版本的 RPM
|
||||
在 Fedora 中安装替代版本的 RPM 包
|
||||
======
|
||||
|
||||
![][1]
|
||||
|
||||
[模块化][2](Modularity)使 Fedora 能够在仓库中提供替代版本的 RPM 软件包。为每个 Fedroa 版本原生构建了多个不同的应用、语言运行时和工具版本。
|
||||
<ruby>[模块化][2]<rt>Modularity</rt></ruby>使 Fedora 能够在仓库中提供替代版本的 RPM 软件包。每个 Fedroa 版本可以原生构建不同应用、语言运行时和工具版本的多个版本。
|
||||
|
||||
Fedora Magazine 大约一年前就写了 [Fedora 28 服务器版的模块化][3]。那时,它只是一个有附加内容的可选仓库,并且明确只支持服务器版。到目前为止,它已经发生了很多变化,现在**模块化是 Fedora 发行版的核心部分**。一些软件包已完全变成模块。在编写本文时,Fedora 30 的 49,464 个二进制 RPM 软件包中的 1,119(2.26%)来自一个模块([关于这个数字的更多信息][4])。
|
||||
Fedora Magazine 大约一年前就写了 [Fedora 28 服务器版的模块化][3]。那时,它只是一个有附加内容的可选仓库,并且明确只支持服务器版。到目前为止,它已经发生了很多变化,现在**模块化是 Fedora 发行版的核心部分**。一些软件包已完全变成模块。在编写本文时,Fedora 30 的 49,464 个二进制 RPM 软件包中的 1,119(2.26%)来自模块([关于这个数字的更多信息][4])。
|
||||
|
||||
### 模块化基础知识
|
||||
|
||||
由于许多软件包有不同的版本会让人难以承受(并且难以管理),所以包被分组为**模块**,这代表一个应用程序、一个语言运行时或任何其他合理的组。
|
||||
由于许多软件包有不同的版本会让人难以承受(并且难以管理),所以包被分组为**模块**,它可以代表一个应用程序、一个语言运行时或任何其他合理的组。
|
||||
|
||||
模块通常有多个**流**,这通常代表软件的主要版本。它可以并行使用,但在给定系统上只能安装每个模块的一个流。
|
||||
|
||||
@ -28,9 +28,9 @@ Fedora Magazine 大约一年前就写了 [Fedora 28 服务器版的模块化][3]
|
||||
|
||||
### 实际使用模块化
|
||||
|
||||
当你在 Fedora 系统上安装 RPM 软件包时,它很可能它来自模块流。你可能没有注意到的原因之一是模块化的核心原则之一是在你要了解之前保持不可见。
|
||||
当你在 Fedora 系统上安装 RPM 软件包时,它很可能它来自模块流。你可能没有注意到的原因之一是模块化的核心原则之一是在你探究之前保持不可见。
|
||||
|
||||
让我们比较以下两种情况。首先,安装流行的 _i3_ 平铺窗口管理器,然后安装极简化的 _dwm_ 窗口管理器:
|
||||
让我们比较以下两种情况。首先,安装流行的 i3 平铺窗口管理器,然后安装极简化的 dwm 窗口管理器:
|
||||
|
||||
```
|
||||
$ sudo dnf install i3
|
||||
@ -38,7 +38,7 @@ $ sudo dnf install i3
|
||||
Done!
|
||||
```
|
||||
|
||||
正如所料,上面的命令会在系统上安装 _i3_ 包及其依赖项。这里没有其他事情发生。但另一个会怎么样?
|
||||
正如所料,上面的命令会在系统上安装 i3 包及其依赖项。这里没有其他事情发生。但另一个会怎么样?
|
||||
|
||||
```
|
||||
$ sudo dnf install dwm
|
||||
@ -49,11 +49,11 @@ Enabling module streams:
|
||||
Done!
|
||||
```
|
||||
|
||||
感觉是一样的,但后台发生了一些事情 。它启用了默认的 _dwm_ 模块流 (_6.1_),并且安装了模块中的 _dwm_ 包。
|
||||
感觉是一样的,但后台发生了一些事情 。它启用了默认的 dwm 模块流(6.1),并且安装了模块中的 dwm 包。
|
||||
|
||||
为了保持透明,输出中有一条关于模块自动启用的消息。但除此之外,用户不需要了解模块化的任何信息,以便按照他们一贯的方式使用他们的系统。
|
||||
|
||||
但如果他们使用模块化方式呢?让我们看看如何安装不同版本的 _dwm_。
|
||||
但如果他们使用模块化方式呢?让我们看看如何安装不同版本的 dwm。
|
||||
|
||||
使用以下命令查看可用的模块流:
|
||||
|
||||
@ -68,9 +68,9 @@ dwm 6.2 ...
|
||||
Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled
|
||||
```
|
||||
|
||||
输出显示 _dwm_ 模块有四个流,_6.1_ 是默认值。
|
||||
输出显示 dwm 模块有四个流,6.1 是默认值。
|
||||
|
||||
要安装不同版本的 _dwm_ 包,例如,安装 _6.2_ 的流。启用他,然后使用以下两个命令安装软件包:
|
||||
要安装不同版本的 dwm 包,例如,安装 6.2 的流。启用它,然后使用以下两个命令安装软件包:
|
||||
|
||||
```
|
||||
$ sudo dnf module enable dwm:6.2
|
||||
@ -120,7 +120,7 @@ via: https://fedoramagazine.org/installing-alternative-rpm-versions-in-fedora/
|
||||
作者:[Adam Šamalík][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[geekpi](https://github.com/geekpi)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
@ -128,6 +128,6 @@ via: https://fedoramagazine.org/installing-alternative-rpm-versions-in-fedora/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://fedoramagazine.org/wp-content/uploads/2019/06/modularity-f30-816x345.jpg
|
||||
[2]: https://docs.pagure.org/modularity
|
||||
[3]: https://fedoramagazine.org/modularity-fedora-28-server-edition/
|
||||
[3]: https://linux.cn/article-10479-1.html
|
||||
[4]: https://blog.samalik.com/2019/06/12/counting-modularity-packages.html
|
||||
[5]: https://docs.fedoraproject.org/en-US/modularity/using-modules/
|
@ -1,8 +1,8 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: (wxy)
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: reviewer: (wxy)
|
||||
[#]: publisher: (wxy)
|
||||
[#]: url: (https://linux.cn/article-10998-1.html)
|
||||
[#]: subject: (Open hardware for musicians and music lovers: Headphone, amps, and more)
|
||||
[#]: via: (https://opensource.com/article/19/6/hardware-music)
|
||||
[#]: author: (Michael Weinberg https://opensource.com/users/mweinberg)
|
||||
@ -10,40 +10,39 @@
|
||||
音乐家和音乐爱好者的开放硬件:耳机、放大器等
|
||||
======
|
||||
|
||||
从 3D 打印乐器到将隔空播放声音的设备,有很多可以通过开放硬件项目来制造音乐的方法。
|
||||
> 从 3D 打印乐器到无线播放声音的设备,有很多通过开放硬件项目来奏乐的方法。
|
||||
|
||||
![][1]
|
||||
|
||||
这个世界到处都是很棒的[开源音乐播放器][2],但为什么只是将开源用在播放音乐上呢?你还可以使用开源硬件制造音乐。本文中描述的所有工具都是经过了[开源硬件协会][3](OSHWA)认证的。这意味着你可以自由地构建它们,重新组合它们,或者用它们做任何其他事情。
|
||||
这个世界到处都是很棒的[开源音乐播放器][2],但为什么只是将开源用在播放音乐上呢?你还可以使用开源硬件奏乐。本文中描述的所有工具都是经过了[开源硬件协会][3](OSHWA)认证的。这意味着你可以自由地构建它们,重新组合它们,或者用它们做任何其他事情。
|
||||
|
||||
### 开源乐器
|
||||
|
||||
当你想制作音乐时,乐器始终是一个好的起点。如果你更倾向于传统的的乐器,那么[F-F-Fiddle][4]可能适合你。
|
||||
当你想奏乐时使用乐器总是最好的方式之一。如果你喜欢传统的的乐器,那么 [F-F-Fiddle][4] 可能适合你。
|
||||
|
||||
![F-f-fiddle][5]
|
||||
|
||||
F-F-Fiddle 是一款全尺寸电子小提琴,你可以使用标准桌面 3D 打印机制作([熔丝制造][6])。如果你觉得眼见为真,那么这里有一个 F-F-Fiddle 的视频: https://youtu.be/8NDWVcJJS2Y
|
||||
F-F-Fiddle 是一款全尺寸电子小提琴,你可以使用标准的桌面 3D 打印机制作(采用[熔丝制造][6])。如果你想眼见为真,那么这里有一个 F-F-Fiddle 的视频: https://img.linux.net.cn/static/video/The%20F-F-Fiddle-8NDWVcJJS2Y.mp4
|
||||
|
||||
精通小提琴,但还对一些更具异国情调的东西感兴趣?<ruby>[开源特雷门琴][7]<rt>Open Theremin</rt></ruby>怎么样?
|
||||
如果你精通小提琴,但还对一些更具异国情调的东西感兴趣?<ruby>[开源的特雷门琴][7]<rt>Open Theremin</rt></ruby>怎么样?
|
||||
|
||||
![Open Theremin][8]
|
||||
|
||||
与所有特雷门琴一样,开源特雷门琴可让你在不触碰乐器的情况下播放音乐。当然,它特别擅长为你的下一个科幻视频或空间主题派对制作[令人毛骨悚然的空间声音][9]。
|
||||
|
||||
[Waft][10] 的操作类似,也可以远程控制声音。它使用[激光雷达][11]来测量手与传感器的距离。看看这个: https://vimeo.com/203705197
|
||||
[Waft][10] 的操作类似,也可以远程控制声音。它使用[激光雷达][11]来测量手与传感器的距离。看看这个: https://img.linux.net.cn/static/video/Waft%20Prototype%2012-Feb-2017-203705197.mp4
|
||||
|
||||
Waft 是特雷门琴吗?我不确定算不算,特雷门琴高手可以在下面的评论里发表一下看法。
|
||||
|
||||
如果特雷门琴对你来说太熟悉了,[SIGNUM][12]可能就是你想要的。用其开发人员的话说,SIGNUM 通过将不可见的无线通信转换为可听信号来“揭示加密的信息代码和人/机通信的语言”。
|
||||
如果特雷门琴对你来说太熟悉了,[SIGNUM][12] 可能就是你想要的。用其开发人员的话说,SIGNUM 通过将不可见的无线通信转换为可听信号来“揭示加密的信息代码和人/机通信的语言”。
|
||||
|
||||
![SIGNUM][13]
|
||||
|
||||
这是演示: https://vimeo.com/142831757
|
||||
|
||||
这是演示: https://img.linux.net.cn/static/video/SIGNUM_Portable%20Analog%20Instrumentation%20Amplifier-142831757.mp4
|
||||
|
||||
### 输入
|
||||
|
||||
无论你使用什么乐器,都需要将其插入某些东西。如果你想要连接到树莓派,请尝试 [AudioSense-Pi][14],它允许你一次将多个输入和输出连接到你的树莓派。
|
||||
无论你使用什么乐器,都需要将其接到某些东西上。如果你想要连接到树莓派,请尝试 [AudioSense-Pi][14],它允许你一次将多个输入和输出连接到你的树莓派。
|
||||
|
||||
![AudioSense-Pi][15]
|
||||
|
||||
@ -55,7 +54,7 @@ Waft 是特雷门琴吗?我不确定算不算,特雷门琴高手可以在下
|
||||
|
||||
### 耳机
|
||||
|
||||
制作所有这些音乐很棒,但你还需要考虑如何听它。幸运的是,[EQ-1耳机][18]是开源和可以 3D 打印的。
|
||||
制作所有这些音乐很棒,但你还需要考虑如何听它。幸运的是,[EQ-1耳机][18]是开源,支持 3D 打印。
|
||||
|
||||
![EQ-1 headphones][19]
|
||||
|
||||
@ -68,7 +67,7 @@ via: https://opensource.com/article/19/6/hardware-music
|
||||
作者:[Michael Weinberg][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[wxy](https://github.com/wxy)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
校对:[wxy](https://github.com/wxy)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
@ -0,0 +1,63 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Cracks appear in Intel’s grip on supercomputing)
|
||||
[#]: via: (https://www.networkworld.com/article/3403443/cracks-appear-in-intels-grip-on-supercomputing.html)
|
||||
[#]: author: (Andy Patrizio https://www.networkworld.com/author/Andy-Patrizio/)
|
||||
|
||||
Cracks appear in Intel’s grip on supercomputing
|
||||
======
|
||||
New competitors threaten to take Intel’s dominance in the high-performance computing (HPC) world, and we’re not even talking about AMD (yet).
|
||||
![Randy Wong/LLNL][1]
|
||||
|
||||
It’s June, so it’s that time again for the twice-yearly Top 500 supercomputer list, where bragging rights are established or, in most cases, reaffirmed. The list constantly shifts as new trends appear, and one of them might be a break in Intel’s dominance.
|
||||
|
||||
[Supercomputers in the top 10 list][2] include a lot of IBM Power-based systems, and almost all run Nvidia GPUs. But there’s more going on than that.
|
||||
|
||||
For starters, an ARM supercomputer has shown up, at #156. [Astra][3] at Sandia National Laboratories is an HPE system running Cavium (now Marvell) ThunderX2 processors. It debuted on the list at #204 last November, but thanks to upgrades, it has moved up the list. It won’t be the last ARM server to show up, either.
|
||||
|
||||
**[ Also see:[10 of the world's fastest supercomputers][2] | Get daily insights: [Sign up for Network World newsletters][4] ]**
|
||||
|
||||
Second is the appearance of four Nvidia DGX servers, with the [DGX SuperPOD][5] ranking the highest at #22. [DGX systems][6] are basically compact GPU boxes with a Xeon just to boot the thing. The GPUs do all the heavy lifting.
|
||||
|
||||
AMD hasn’t shown up yet with the Epyc processors, but it will, given Cray is building them for the government.
|
||||
|
||||
This signals a breaking up of the hold Intel has had on the high-performance computing (HPC) market for a long time, said Ashish Nadkarni, group vice president in IDC's worldwide infrastructure practice. “The Intel hold has already been broken up by all the accelerators in the supercomputing space. The more accelerators they use, the less need they have for Xeons. They can go with other processors that do justice to those accelerators,” he told me.
|
||||
|
||||
With so much work in HPC and artificial intelligence (AI) being done by GPUs, the x86 processor becomes just a boot processor in a way. I wasn’t kidding about the DGX box. It’s got one Xeon and eight Tesla GPUs. And the Xeon is an E5, a midrange part.
|
||||
|
||||
**[[Get certified as an Apple Technical Coordinator with this seven-part online course from PluralSight.][7] ]**
|
||||
|
||||
“They don’t need high-end Xeons in servers any more, although there’s a lot of supercomputers that just use CPUs. The fact is there are so many options now,” said Nadkarni. One example of an all-CPU system is [Frontera][8], a Dell-based system at the Texas Advanced Computing Center in Austin.
|
||||
|
||||
The top two computers, Sierra and Summit, both run IBM Power9 RISC processors, as well as Nvidia GPUs. All told, Nvidia is in 125 of the 500 supercomputers, including five of the top 10, the fastest computer in the world, the fastest in Europe (Piz Daint) and the fastest in Japan (ABCI).
|
||||
|
||||
Lenovo was the top hardware provider, beating out Dell, HPE, and IBM combined. That’s because of its large presence in its native China. Nadkari said Lenovo, which acquired the IBM x86 server business in 2014, has benefitted from the IBM installed base, which has continued wanting the same tech from Lenovo under new ownership.
|
||||
|
||||
Join the Network World communities on [Facebook][9] and [LinkedIn][10] to comment on topics that are top of mind.
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://www.networkworld.com/article/3403443/cracks-appear-in-intels-grip-on-supercomputing.html
|
||||
|
||||
作者:[Andy Patrizio][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://www.networkworld.com/author/Andy-Patrizio/
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://images.idgesg.net/images/article/2018/10/sierra875x500-100778404-large.jpg
|
||||
[2]: https://www.networkworld.com/article/3236875/embargo-10-of-the-worlds-fastest-supercomputers.html
|
||||
[3]: https://www.top500.org/system/179565
|
||||
[4]: https://www.networkworld.com/newsletters/signup.html
|
||||
[5]: https://www.top500.org/system/179691
|
||||
[6]: https://www.networkworld.com/article/3196088/nvidias-new-volta-based-dgx-1-supercomputer-puts-400-servers-in-a-box.html
|
||||
[7]: https://pluralsight.pxf.io/c/321564/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fpaths%2Fapple-certified-technical-trainer-10-11
|
||||
[8]: https://www.networkworld.com/article/3236875/embargo-10-of-the-worlds-fastest-supercomputers.html#slide7
|
||||
[9]: https://www.facebook.com/NetworkWorld/
|
||||
[10]: https://www.linkedin.com/company/network-world
|
@ -0,0 +1,62 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (The office coffee model of concurrent garbage collection)
|
||||
[#]: via: (https://dave.cheney.net/2018/12/28/the-office-coffee-model-of-concurrent-garbage-collection)
|
||||
[#]: author: (Dave Cheney https://dave.cheney.net/author/davecheney)
|
||||
|
||||
The office coffee model of concurrent garbage collection
|
||||
======
|
||||
|
||||
Garbage collection is a field with its own terminology. Concepts like like _mutator_ s, _card marking_ , and _write barriers_ create a hurdle to understanding how garbage collectors work. Here’s an analogy to explain the operations of a concurrent garbage collector using everyday items found in the workplace.
|
||||
|
||||
Before we discuss the operation of _concurrent_ garbage collection, let’s introduce the dramatis personae. In offices around the world you’ll find one of these:
|
||||
|
||||
![][1]
|
||||
|
||||
In the workplace coffee is a natural resource. Employees visit the break room and fill their cups as required. That is, until the point someone goes to fill their cup only to discover the pot is _empty_!
|
||||
|
||||
Immediately the office is thrown into chaos. Meeting are called. Investigations are held. The perpetrator who took the last cup without refilling the machine is found and [reprimanded][2]. Despite many passive aggressive notes the situation keeps happening, thus a committee is formed to decide if a larger coffee pot should be requisitioned. Once the coffee maker is again full office productivity slowly returns to normal.
|
||||
|
||||
This is the model of _stop the world_ garbage collection. The various parts of your program proceed through their day consuming memory, or in our analogy coffee, without a care about the next allocation that needs to be made. Eventually one unlucky attempt to allocate memory is made only to find the heap, or the coffee pot, exhausted, triggering a stop the world garbage collection.
|
||||
|
||||
* * *
|
||||
|
||||
Down the road at a more enlightened workplace, management have adopted a different strategy for mitigating their break room’s coffee problems. Their policy is simple: if the pot is more than half full, fill your cup and be on your way. However, if the pot is less than half full, _before_ filling your cup, you must add a little coffee and a little water to the top of the machine. In this way, by the time the next person arrives for their re-up, the level in the pot will hopefully have risen higher than when the first person found it.
|
||||
|
||||
This policy does come at a cost to office productivity. Rather than filling their cup and hoping for the best, each worker may, depending on the aggregate level of consumption in the office, have to spend a little time refilling the percolator and topping up the water. However, this is time spent by a person who was already heading to the break room. It costs a few extra minutes to maintain the coffee machine, but does not impact their officemates who aren’t in need of caffeination. If several people take a break at the same time, they will all find the level in the pot below the half way mark and all proceed to top up the coffee maker–the more consumption, the greater the rate the machine will be refilled, although this takes a little longer as the break room becomes congested.
|
||||
|
||||
This is the model of _concurrent garbage collection_ as practiced by the Go runtime (and probably other language runtimes with concurrent collectors). Rather than each heap allocation proceeding blindly until the heap is exhausted, leading to a long stop the world pause, concurrent collection algorithms spread the work of walking the heap to find memory which is no longer reachable over the parts of the program allocating memory. In this way the parts of the program which allocate memory each pay a small cost–in terms of latency–for those allocations rather than the whole program being forced to halt when the heap is exhausted.
|
||||
|
||||
Lastly, in keeping with the office coffee model, if the rate of coffee consumption in the office is so high that management discovers that their staff are always in the break room trying desperately to refill the coffee machine, it’s time to invest in a machine with a bigger pot–or in garbage collection terms, grow the heap.
|
||||
|
||||
### Related posts:
|
||||
|
||||
1. [Visualising the Go garbage collector][3]
|
||||
2. [A whirlwind tour of Go’s runtime environment variables][4]
|
||||
3. [Why is a Goroutine’s stack infinite ?][5]
|
||||
4. [Introducing Go 2.0][6]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dave.cheney.net/2018/12/28/the-office-coffee-model-of-concurrent-garbage-collection
|
||||
|
||||
作者:[Dave Cheney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://dave.cheney.net/author/davecheney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://dave.cheney.net/wp-content/uploads/2018/12/20181204175004_79256.jpg
|
||||
[2]: https://www.youtube.com/watch?v=ww86iaucd2A
|
||||
[3]: https://dave.cheney.net/2014/07/11/visualising-the-go-garbage-collector (Visualising the Go garbage collector)
|
||||
[4]: https://dave.cheney.net/2015/11/29/a-whirlwind-tour-of-gos-runtime-environment-variables (A whirlwind tour of Go’s runtime environment variables)
|
||||
[5]: https://dave.cheney.net/2013/06/02/why-is-a-goroutines-stack-infinite (Why is a Goroutine’s stack infinite ?)
|
||||
[6]: https://dave.cheney.net/2016/10/25/introducing-go-2-0 (Introducing Go 2.0)
|
@ -0,0 +1,57 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Avoid package names like base, util, or common)
|
||||
[#]: via: (https://dave.cheney.net/2019/01/08/avoid-package-names-like-base-util-or-common)
|
||||
[#]: author: (Dave Cheney https://dave.cheney.net/author/davecheney)
|
||||
|
||||
Avoid package names like base, util, or common
|
||||
======
|
||||
|
||||
Writing a good Go package starts with its name. Think of your package’s name as an elevator pitch, you have to describe what it does using just one word.
|
||||
|
||||
A common cause of poor package names are _utility packages_. These are packages where helpers and utility code congeal. These packages contain an assortment of unrelated functions, as such their utility is hard to describe in terms of what the package _provides_. This often leads to a package’s name being derived from what the package _contains_ —utilities.
|
||||
|
||||
Package names like `utils` or `helpers` are commonly found in projects which have developed deep package hierarchies and want to share helper functions without introducing import loops. Extracting utility functions to new package breaks the import loop, but as the package stems from a design problem in the project, its name doesn’t reflect its purpose, only its function in breaking the import cycle.
|
||||
|
||||
> [A little] duplication is far cheaper than the wrong abstraction.
|
||||
|
||||
— [Sandy Metz][1]
|
||||
|
||||
My recommendation to improve the name of `utils` or `helpers` packages is to analyse where they are imported and move the relevant functions into the calling package. Even if this results in some code duplication this is preferable to introducing an import dependency between two packages. In the case where utility functions are used in many places, prefer multiple packages, each focused on a single aspect with a correspondingly descriptive name.
|
||||
|
||||
Packages with names like `base` or `common` are often found when functionality common to two or more related facilities, for example common types between a client and server or a server and its mock, has been refactored into a separate package. Instead the solution is to reduce the number of packages by combining client, server, and common code into a single package named after the facility the package provides.
|
||||
|
||||
For example, the `net/http` package does not have `client` and `server` packages, instead it has `client.go` and `server.go` files, each holding their respective types. `transport.go` holds for the common message transport code used by both HTTP clients and servers.
|
||||
|
||||
Name your packages after what they _provide_ , not what they _contain_.
|
||||
|
||||
### Related posts:
|
||||
|
||||
1. [Simple profiling package moved, updated][2]
|
||||
2. [The package level logger anti pattern][3]
|
||||
3. [How to include C code in your Go package][4]
|
||||
4. [Why I think Go package management is important][5]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dave.cheney.net/2019/01/08/avoid-package-names-like-base-util-or-common
|
||||
|
||||
作者:[Dave Cheney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://dave.cheney.net/author/davecheney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://www.sandimetz.com/blog/2016/1/20/the-wrong-abstraction
|
||||
[2]: https://dave.cheney.net/2014/10/22/simple-profiling-package-moved-updated (Simple profiling package moved, updated)
|
||||
[3]: https://dave.cheney.net/2017/01/23/the-package-level-logger-anti-pattern (The package level logger anti pattern)
|
||||
[4]: https://dave.cheney.net/2013/09/07/how-to-include-c-code-in-your-go-package (How to include C code in your Go package)
|
||||
[5]: https://dave.cheney.net/2013/10/10/why-i-think-go-package-management-is-important (Why I think Go package management is important)
|
@ -0,0 +1,204 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (Eliminate error handling by eliminating errors)
|
||||
[#]: via: (https://dave.cheney.net/2019/01/27/eliminate-error-handling-by-eliminating-errors)
|
||||
[#]: author: (Dave Cheney https://dave.cheney.net/author/davecheney)
|
||||
|
||||
Eliminate error handling by eliminating errors
|
||||
======
|
||||
|
||||
Go 2 aims to improve the overhead of [error handling][1], but do you know what is better than an improved syntax for handling errors? Not needing to handle errors at all. Now, I’m not saying “delete your error handling code”, instead I’m suggesting changing your code so you don’t have as many errors to handle.
|
||||
|
||||
This article draws inspiration from a chapter in John Ousterhout’s, _[A philosophy of Software Design,][2]_ “Define Errors Out of Existence”. I’m going to try to apply his advice to Go.
|
||||
|
||||
* * *
|
||||
|
||||
Here’s a function to count the number of lines in a file,
|
||||
|
||||
```
|
||||
func CountLines(r io.Reader) (int, error) {
|
||||
var (
|
||||
br = bufio.NewReader(r)
|
||||
lines int
|
||||
err error
|
||||
)
|
||||
|
||||
for {
|
||||
_, err = br.ReadString('\n')
|
||||
lines++
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if err != io.EOF {
|
||||
return 0, err
|
||||
}
|
||||
return lines, nil
|
||||
}
|
||||
```
|
||||
|
||||
We construct a `bufio.Reader`, then sit in a loop calling the `ReadString` method, incrementing a counter until we reach the end of the file, then we return the number of lines read. That’s the code we _wanted_ to write, instead `CountLines` is made more complicated by its error handling. For example, there is this strange construction:
|
||||
|
||||
```
|
||||
_, err = br.ReadString('\n')
|
||||
lines++
|
||||
if err != nil {
|
||||
break
|
||||
}
|
||||
```
|
||||
|
||||
We increment the count of lines _before_ checking the error—that looks odd. The reason we have to write it this way is `ReadString` will return an error if it encounters an end-of-file—`io.EOF`—before hitting a newline character. This can happen if there is no trailing newline.
|
||||
|
||||
To address this problem, we rearrange the logic to increment the line count, then see if we need to exit the loop.1
|
||||
|
||||
But we’re not done checking errors yet. `ReadString` will return `io.EOF` when it hits the end of the file. This is expected, `ReadString` needs some way of saying _stop, there is nothing more to read_. So before we return the error to the caller of `CountLine`, we need to check if the error was _not_ `io.EOF`, and in that case propagate it up, otherwise we return `nil` to say that everything worked fine. This is why the final line of the function is not simply
|
||||
|
||||
```
|
||||
return lines, err
|
||||
```
|
||||
|
||||
I think this is a good example of Russ Cox’s [observation that error handling can obscure the operation of the function][3]. Let’s look at an improved version.
|
||||
|
||||
```
|
||||
func CountLines(r io.Reader) (int, error) {
|
||||
sc := bufio.NewScanner(r)
|
||||
lines := 0
|
||||
|
||||
for sc.Scan() {
|
||||
lines++
|
||||
}
|
||||
|
||||
return lines, sc.Err()
|
||||
}
|
||||
```
|
||||
|
||||
This improved version switches from using `bufio.Reader` to `bufio.Scanner`. Under the hood `bufio.Scanner` uses `bufio.Reader` adding a layer of abstraction which helps remove the error handling which obscured the operation of our previous version of `CountLines` 2
|
||||
|
||||
The method `sc.Scan()` returns `true` if the scanner _has_ matched a line of text and _has not_ encountered an error. So, the body of our `for` loop will be called only when there is a line of text in the scanner’s buffer. This means our revised `CountLines` correctly handles the case where there is no trailing newline, It also correctly handles the case where the file is empty.
|
||||
|
||||
Secondly, as `sc.Scan` returns `false` once an error is encountered, our `for` loop will exit when the end-of-file is reached or an error is encountered. The `bufio.Scanner` type memoises the first error it encounters and we recover that error once we’ve exited the loop using the `sc.Err()` method.
|
||||
|
||||
Lastly, `buffo.Scanner` takes care of handling `io.EOF` and will convert it to a `nil` if the end of file was reached without encountering another error.
|
||||
|
||||
* * *
|
||||
|
||||
My second example is inspired by Rob Pikes’ _[Errors are values][4]_ blog post.
|
||||
|
||||
When dealing with opening, writing and closing files, the error handling is present but not overwhelming as, the operations can be encapsulated in helpers like `ioutil.ReadFile` and `ioutil.WriteFile`. However, when dealing with low level network protocols it often becomes necessary to build the response directly using I/O primitives, thus the error handling can become repetitive. Consider this fragment of a HTTP server which is constructing a HTTP/1.1 response.
|
||||
|
||||
```
|
||||
type Header struct {
|
||||
Key, Value string
|
||||
}
|
||||
|
||||
type Status struct {
|
||||
Code int
|
||||
Reason string
|
||||
}
|
||||
|
||||
func WriteResponse(w io.Writer, st Status, headers []Header, body io.Reader) error {
|
||||
_, err := fmt.Fprintf(w, "HTTP/1.1 %d %s\r\n", st.Code, st.Reason)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, h := range headers {
|
||||
_, err := fmt.Fprintf(w, "%s: %s\r\n", h.Key, h.Value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := fmt.Fprint(w, "\r\n"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(w, body)
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
First we construct the status line using `fmt.Fprintf`, and check the error. Then for each header we write the header key and value, checking the error each time. Lastly we terminate the header section with an additional `\r\n`, check the error, and copy the response body to the client. Finally, although we don’t need to check the error from `io.Copy`, we do need to translate it from the two return value form that `io.Copy` returns into the single return value that `WriteResponse` expects.
|
||||
|
||||
Not only is this a lot of repetitive work, each operation—fundamentally writing bytes to an `io.Writer`—has a different form of error handling. But we can make it easier on ourselves by introducing a small wrapper type.
|
||||
|
||||
```
|
||||
type errWriter struct {
|
||||
io.Writer
|
||||
err error
|
||||
}
|
||||
|
||||
func (e *errWriter) Write(buf []byte) (int, error) {
|
||||
if e.err != nil {
|
||||
return 0, e.err
|
||||
}
|
||||
|
||||
var n int
|
||||
n, e.err = e.Writer.Write(buf)
|
||||
return n, nil
|
||||
}
|
||||
```
|
||||
|
||||
`errWriter` fulfils the `io.Writer` contract so it can be used to wrap an existing `io.Writer`. `errWriter` passes writes through to its underlying writer until an error is detected. From that point on, it discards any writes and returns the previous error.
|
||||
|
||||
```
|
||||
func WriteResponse(w io.Writer, st Status, headers []Header, body io.Reader) error {
|
||||
ew := &errWriter{Writer: w}
|
||||
fmt.Fprintf(ew, "HTTP/1.1 %d %s\r\n", st.Code, st.Reason)
|
||||
|
||||
for _, h := range headers {
|
||||
fmt.Fprintf(ew, "%s: %s\r\n", h.Key, h.Value)
|
||||
}
|
||||
|
||||
fmt.Fprint(ew, "\r\n")
|
||||
io.Copy(ew, body)
|
||||
|
||||
return ew.err
|
||||
}
|
||||
```
|
||||
|
||||
Applying `errWriter` to `WriteResponse` dramatically improves the clarity of the code. Each of the operations no longer needs to bracket itself with an error check. Reporting the error is moved to the end of the function by inspecting the `ew.err` field, avoiding the annoying translation from `io.Copy`’s return values.
|
||||
|
||||
* * *
|
||||
|
||||
When you find yourself faced with overbearing error handling, try to extract some of the operations into a helper type.
|
||||
|
||||
1. This logic _still_ isn’t correct, can you spot the bug?
|
||||
2. `bufio.Scanner` can scan for any pattern, by default it looks for newlines.
|
||||
|
||||
|
||||
|
||||
### Related posts:
|
||||
|
||||
1. [Error handling vs. exceptions redux][5]
|
||||
2. [Stack traces and the errors package][6]
|
||||
3. [Subcommand handling in Go][7]
|
||||
4. [Constant errors][8]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dave.cheney.net/2019/01/27/eliminate-error-handling-by-eliminating-errors
|
||||
|
||||
作者:[Dave Cheney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://dave.cheney.net/author/davecheney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://go.googlesource.com/proposal/+/master/design/go2draft-error-handling-overview.md
|
||||
[2]: https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201
|
||||
[3]: https://www.youtube.com/watch?v=6wIP3rO6On8
|
||||
[4]: https://blog.golang.org/errors-are-values
|
||||
[5]: https://dave.cheney.net/2014/11/04/error-handling-vs-exceptions-redux (Error handling vs. exceptions redux)
|
||||
[6]: https://dave.cheney.net/2016/06/12/stack-traces-and-the-errors-package (Stack traces and the errors package)
|
||||
[7]: https://dave.cheney.net/2013/11/07/subcommand-handling-in-go (Subcommand handling in Go)
|
||||
[8]: https://dave.cheney.net/2016/04/07/constant-errors (Constant errors)
|
@ -0,0 +1,83 @@
|
||||
[#]: collector: (lujun9972)
|
||||
[#]: translator: ( )
|
||||
[#]: reviewer: ( )
|
||||
[#]: publisher: ( )
|
||||
[#]: url: ( )
|
||||
[#]: subject: (You shouldn’t name your variables after their types for the same reason you wouldn’t name your pets “dog” or “cat”)
|
||||
[#]: via: (https://dave.cheney.net/2019/01/29/you-shouldnt-name-your-variables-after-their-types-for-the-same-reason-you-wouldnt-name-your-pets-dog-or-cat)
|
||||
[#]: author: (Dave Cheney https://dave.cheney.net/author/davecheney)
|
||||
|
||||
You shouldn’t name your variables after their types for the same reason you wouldn’t name your pets “dog” or “cat”
|
||||
======
|
||||
|
||||
The name of a variable should describe its contents, not the _type_ of the contents. Consider this example:
|
||||
|
||||
```
|
||||
var usersMap map[string]*User
|
||||
```
|
||||
|
||||
What are some good properties of this declaration? We can see that it’s a map, and it has something to do with the `*User` type, so that’s probably good. But `usersMap` _is_ a map and Go, being a statically typed language, won’t let us accidentally use a map where a different type is required, so the `Map` suffix as a safety precaution is redundant.
|
||||
|
||||
Now, consider what happens if we declare other variables using this pattern:
|
||||
|
||||
```
|
||||
var (
|
||||
companiesMap map[string]*Company
|
||||
productsMap map[string]*Products
|
||||
)
|
||||
```
|
||||
|
||||
Now we have three map type variables in scope, `usersMap`, `companiesMap`, and `productsMap`, all mapping `string`s to different `struct` types. We know they are maps, and we also know that their declarations prevent us from using one in place of another—the compiler will throw an error if we try to use `companiesMap` where the code is expecting a `map[string]*User`. In this situation it’s clear that the `Map` suffix does not improve the clarity of the code, its just extra boilerplate to type.
|
||||
|
||||
My suggestion is avoid any suffix that resembles the _type_ of the variable. Said another way, if `users` isn’t descriptive enough, then `usersMap` won’t be either.
|
||||
|
||||
This advice also applies to function parameters. For example:
|
||||
|
||||
```
|
||||
type Config struct {
|
||||
//
|
||||
}
|
||||
|
||||
func WriteConfig(w io.Writer, config *Config)
|
||||
```
|
||||
|
||||
Naming the `*Config` parameter `config` is redundant. We know it’s a pointer to a `Config`, it says so right there in the declaration. Instead consider if `conf` will do, or maybe just `c` if the lifetime of the variable is short enough.
|
||||
|
||||
This advice is more than just a desire for brevity. If there is more that one `*Config` in scope at any one time, calling them `config1` and `config2` is less descriptive than calling them `original` and `updated` . The latter are less likely to be accidentally transposed—something the compiler won’t catch—while the former differ only in a one character suffix.
|
||||
|
||||
Finally, don’t let package names steal good variable names. The name of an imported identifier includes its package name. For example the `Context` type in the `context` package will be known as `context.Context` when imported into another package . This makes it impossible to use `context` as a variable or type, unless of course you rename the import, but that’s throwing good after bad. This is why the local declaration for `context.Context` types is traditionally `ctx`. eg.
|
||||
|
||||
```
|
||||
func WriteLog(ctx context.Context, message string)
|
||||
```
|
||||
|
||||
* * *
|
||||
|
||||
A variable’s name should be independent of its type. You shouldn’t name your variables after their types for the same reason you wouldn’t name your pets “dog” or “cat”. You shouldn’t include the name of your type in the name of your variable for the same reason.
|
||||
|
||||
### Related posts:
|
||||
|
||||
1. [On declaring variables][1]
|
||||
2. [Go, without package scoped variables][2]
|
||||
3. [A whirlwind tour of Go’s runtime environment variables][3]
|
||||
4. [Declaration scopes in Go][4]
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
via: https://dave.cheney.net/2019/01/29/you-shouldnt-name-your-variables-after-their-types-for-the-same-reason-you-wouldnt-name-your-pets-dog-or-cat
|
||||
|
||||
作者:[Dave Cheney][a]
|
||||
选题:[lujun9972][b]
|
||||
译者:[译者ID](https://github.com/译者ID)
|
||||
校对:[校对者ID](https://github.com/校对者ID)
|
||||
|
||||
本文由 [LCTT](https://github.com/LCTT/TranslateProject) 原创编译,[Linux中国](https://linux.cn/) 荣誉推出
|
||||
|
||||
[a]: https://dave.cheney.net/author/davecheney
|
||||
[b]: https://github.com/lujun9972
|
||||
[1]: https://dave.cheney.net/2014/05/24/on-declaring-variables (On declaring variables)
|
||||
[2]: https://dave.cheney.net/2017/06/11/go-without-package-scoped-variables (Go, without package scoped variables)
|
||||
[3]: https://dave.cheney.net/2015/11/29/a-whirlwind-tour-of-gos-runtime-environment-variables (A whirlwind tour of Go’s runtime environment variables)
|
||||
[4]: https://dave.cheney.net/2016/12/15/declaration-scopes-in-go (Declaration scopes in Go)
|
Loading…
Reference in New Issue
Block a user