2023年11月

这是一个小小的 CLI 工具,可在 Linux 终端中添加水族箱。

Linux 的众多命令工具 里,有一部分偏向于休闲娱乐而非工作。Asciiquarium 就是一个很好的例子。

Asciiquarium 为 Linux 终端提供了以 ASCII 格式构建的简单的水族馆动画效果。

看起来有趣吗?我们一起进一步了解。

如何在 Linux 中安装 Asciiquarium

如果你是 Arch Linux 或 Fedora 用户,你可以直接从官方仓库中安装。

Fedora 的用户请运行:

sudo dnf install asciiquarium

而 Arch Linux 用户请运行:

sudo pacman -S asciiquarium

对于 Ubuntu,Asciiquarium 没有包含在默认仓库里。因此,你需要选择使用预编译的二进制文件,或者一些外部的 PPA。

使用 PPA 安装 Asciiquarium

首先,添加 Asciiquarium 的 PPA:

sudo add-apt-repository ppa:ytvwld/asciiquarium
sudo apt update

然后,安装相关的软件包和依赖:

sudo apt install asciiquarium
删除 PPA

在你删除 Asciiquarium 的 PPA 之前,首先要移除相关软件包。

sudo apt purge asciiquarium
sudo apt autoremove

然后,从系统中移除 PPA:

sudo add-apt-repository --remove ppa:openshot.developers/ppa
sudo apt update

使用二进制文件安装 Asciiquarium

? 你需要为你的系统单独安装一些 Perl 模块。同时,它将在你的系统中安装几个与 Perl 相关的包,所以请注意。

安装 Perl 依赖包

要运行二进制文件,你需要从 CPAN 中安装 Animation 和 Curses 模块。

在 Ubuntu 中安装 CPAN:

sudo apt install cpanminus libcurses-perl

接着,运行:

cpan Term::Animation

Animation 模块安装

该操作会要求你做一些配置,只需选取默认值即可。全部设置好后,来下载 Asciiquarium 的发布版。

下载 Asciiquarium

解压文件,你会得到一个名为 Asciiquarium 的文件,接下来,让它具有执行权限。

赋予 Asciiquarium 执行权限

如果你需要通过命令行来完成,只需打开终端,并用 chmod 命令赋予执行权限。

chmod +x asciiquarium

此时,你可以直接在当前目录下运行这个文件以获取动画效果:

./asciiquarium

或者,你也可以把这个文件放在一个 包含在你的 PATH 中的位置上。

如何使用 Asciiquarium

Asciiquarium 使用起来非常简单,它不设任何命令行选项。只需运行 asciiquarium,你就能在终端中看到水族馆的动画效果。

Asciiquarium 动画效果

程序还提供了几个热键支持。

  • r:重绘动画
  • p:暂停/播放动画
  • q:退出程序
?

此外,也可以使用箭头键提升动画的速度。

用 lolcat 加强 Asciiquarium 的体验

如果你想让 Asciiquarium 的颜色更丰富,可以综合使用 lolcat。首先安装 lolcat

sudo apt install lolcat

然后,运行:

asciiquarium | lolcat

Asciiquarium Lolcat 效果

如果你还需要更多的动画效果,可以适当调节 lolcat 的参数,例如:

asciiquarium | lolcat -p 200

Asciiquarium 和 lolcat 的效果调整

这样操作会产生各种不同的颜色效果。

你还可以使用 lolcat-i 选项,来反转颜色:

asciiquarium | lolcat -i -p 200

颜色反转效果

赠品:XFishTank(让你的桌面诠释海底世界)

还有一个类似的有趣命令叫做 xfishtank。它在你的根窗口,即桌面,创建一片海洋世界。你可以从 Ubuntu 的官方仓库直接安装 xfishtank

sudo apt install xfishtank

安装完成后,直接运行:

xfishtank

XFishTank 提供了很多选项供你调节,例如鱼儿的数量、气泡等等。你可以参考 该命令的 man 页面 学习更多相关内容。

xfishtank -b 100 -f 15

Xfishtank 效果展示

结语

就像你所看到的,Linux 终端里的小鱼或许不能提供实质性的帮助,但它确实能带给我们愉快的心情。

如果你不是那么喜欢鱼,那么试试看牛吧。

哞~ 我的 Linux 终端里有头牛

希望你在这些有趣的小工具的陪伴下,能够更加享受 Linux 的世界。?

(题图:MJ/83766cba-02e1-4d20-8797-a38e5c17a0c0)


via: https://itsfoss.com/asciiquarium/

作者:Sreenath 选题:lujun9972 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

通过理解解释、即时编译和预先编译之间的区别,有效地使用它们。

Java 是一种跨平台的编程语言。程序源代码会被编译为 字节码 bytecode ,然后字节码在运行时被转换为 机器码 machine code 解释器 interpreter 在物理机器上模拟出的抽象计算机上执行字节码指令。 即时 just-in-time (JIT)编译发生在运行期,而 预先 ahead-of-time (AOT)编译发生在构建期。

本文将说明解释器、JIT 和 AOT 分别何时起作用,以及如何在 JIT 和 AOT 之间权衡。

源代码、字节码、机器码

应用程序通常是由 C、C++ 或 Java 等编程语言编写。用这些高级编程语言编写的指令集合称为源代码。源代码是人类可读的。要在目标机器上执行它,需要将源代码转换为机器可读的机器码。这个转换工作通常是由 编译器 compiler 来完成的。

然而,在 Java 中,源代码首先被转换为一种中间形式,称为字节码。字节码是平台无关的,所以 Java 被称为平台无关编程语言。Java 编译器 javac 将源代码转换为字节码。然后解释器解释执行字节码。

下面是一个简单的 Java 程序, Hello.java

//Hello.java
public class Hello {
    public static void main(String[] args) {
         System.out.println("Inside Hello World!");
    }
}

使用 javac 编译它,生成包含字节码的 Hello.class 文件。

$ javac Hello.java
$ ls
Hello.class  Hello.java

现在,使用 javap 来反汇编 Hello.class 文件的内容。使用 javap 时如果不指定任何选项,它将打印基本信息,包括编译这个 .class 文件的源文件、包名称、公共和受保护字段以及类的方法。

$ javap Hello.class
Compiled from "Hello.java"
public class Hello {
    public Hello();
    public static void main(java.lang.String[]);
}

要查看 .class 文件中的字节码内容,使用 -c 选项:

$ javap -c Hello.class
Compiled from "Hello.java"
public class Hello {
  public Hello();
        Code:
           0: aload_0
           1: invokespecial #1                      // Method java/lang/Object."<init>":()V
           4: return

  public static void main(java.lang.String[]);
        Code:
           0: getstatic         #2                      // Field java/lang/System.out:Ljava/io/PrintStream;
           3: ldc               #3                      // String Inside Hello World!
           5: invokevirtual #4                      // Method    
java/io/PrintStream.println:(Ljava/lang/String;)V
           8: return
}

要获取更详细的信息,使用 -v 选项:

$ javap -v Hello.class

解释器,JIT 和 AOT

解释器负责在物理机器上模拟出的抽象计算机上执行字节码指令。当使用 javac 编译源代码,然后使用 java 执行时,解释器在程序运行时运行并完成它的目标。

$ javac Hello.java
$ java Hello
Inside Hello World!

JIT 编译器也在运行期发挥作用。当解释器解释 Java 程序时,另一个称为运行时 分析器 profiler 的组件将静默地监视程序的执行,统计各部分代码被解释的次数。基于这些统计信息可以检测出程序的 热点 hotspot ,即那些经常被解释的代码。一旦代码被解释次数超过设定的阈值,它们满足被 JIT 编译器直接转换为机器码的条件。所以 JIT 编译器也被称为分析优化的编译器。从字节码到机器码的转换是在程序运行过程中进行的,因此称为即时编译。JIT 减少了解释器将同一组指令模拟为机器码的负担。

AOT 编译器在构建期编译代码。在构建时将需要频繁解释和 JIT 编译的代码直接编译为机器码可以缩短 Java 虚拟机 Java Virtual Machine (JVM) 的 预热 warm-up 时间。(LCTT 译注:Java 程序启动后首先字节码被解释执行,此时执行效率较低。等到程序运行了足够的时间后,代码热点被检测出来,JIT 开始发挥作用,程序运行效率提升。JIT 发挥作用之前的过程就是预热。)AOT 是在 Java 9 中引入的一个实验性特性。jaotc 使用 Graal 编译器(它本身也是用 Java 编写的)来实现 AOT 编译。

Hello.java 为例:

//Hello.java
public class Hello {
    public static void main(String[] args) {
        System.out.println("Inside Hello World!");
    }
}


$ javac Hello.java
$ jaotc --output libHello.so Hello.class
$ java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libHello.so Hello
Inside Hello World!

解释和编译发生的时机

下面通过例子来展示 Java 在什么时候使用解释器,以及 JIT 和 AOT 何时参与进来。这里有一个简单的程序 Demo.java :

//Demo.java
public class Demo {
    public int square(int i) throws Exception {
        return(i*i);
    }


    public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 10; i++) {
            System.out.println("call " + Integer.valueOf(i));
            long a = System.nanoTime();
            Int r = new Demo().square(i);
            System.out.println("Square(i) = " + r);
            long b = System.nanoTime();
            System.out.println("elapsed= " + (b-a));
            System.out.println("--------------------------------");
        }
    }
}

在这个程序的 main() 方法中创建了一个 Demo 对象的实例,并调用该实例的 square()方法,然后显示 for 循环迭代变量的平方值。编译并运行它:

$ javac Demo.java
$ java Demo
1 iteration
Square(i) = 1
Time taken= 8432439
--------------------------------
2 iteration
Square(i) = 4
Time taken= 54631
--------------------------------
.
.
.
--------------------------------
10 iteration
Square(i) = 100
Time taken= 66498
--------------------------------

上面的结果是由谁产生的呢?是解释器,JIT 还是 AOT?在目前的情况下,它完全是通过解释产生的。我是怎么得出这个结论的呢?只有代码被解释的次数必须超过某个阈值时,这些热点代码片段才会被加入 JIT 编译队列。只有这时,JIT 编译才会发挥作用。使用以下命令查看 JDK 11 中的该阈值:

$ java -XX:+PrintFlagsFinal -version | grep CompileThreshold
 intx CompileThreshold     = 10000                                      {pd product} {default}
[...]
openjdk version "11.0.13" 2021-10-19
OpenJDK Runtime Environment 18.9 (build 11.0.13+8)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.13+8, mixed mode, sharing)

上面的输出表明,一段代码被解释 10,000 次才符合 JIT 编译的条件。这个阈值是否可以手动调整呢?是否有 JVM 标志可以指示出方法是否被 JIT 编译了呢?答案是肯定的,而且有多种方式可以达到这个目的。

使用 -XX:+PrintCompilation 选项可以查看一个方法是否被 JIT 编译。除此之外,使用 -Xbatch 标志可以提高输出的可读性。如果解释和 JIT 同时发生,-Xbatch 可以帮助区分两者的输出。使用这些标志如下:

$ java -Xbatch  -XX:+PrintCompilation  Demo
         34        1        b  3           java.util.concurrent.ConcurrentHashMap::tabAt (22 bytes)
         35        2         n 0           jdk.internal.misc.Unsafe::getObjectVolatile (native)   
         35        3        b  3           java.lang.Object::<init> (1 bytes)
[...]
        210  269         n 0           java.lang.reflect.Array::newArray (native)   (static)
        211  270        b  3           java.lang.String::substring (58 bytes)
[...]
--------------------------------
10 iteration
Square(i) = 100
Time taken= 50150
--------------------------------

注意,上面命令的实际输出太长了,这里我只是截取了一部分。输出很长的原因是除了 Demo 程序的代码外,JDK 内部类的函数也被编译了。由于我的重点是 Demo.java 代码,我希望排除内部包的函数来简化输出。通过选项 -XX:CompileCommandFile 可以禁用内部类的 JIT:

$ java -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler Demo

在选项 -XX:CompileCommandFile 指定的文件 hotspot_compiler 中包含了要排除的包:

$ cat hotspot_compiler
quiet
exclude java/* *
exclude jdk/* *
exclude sun/* *

第一行的 quiet 告诉 JVM 不要输出任何关于被排除类的内容。用 -XX:CompileThreshold 将 JIT 阈值设置为 5。这意味着在解释 5 次之后,就会进行 JIT 编译:

$ java -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler \
-XX:CompileThreshold=5 Demo
        47      1       n 0     java.lang.invoke.MethodHandle::linkToStatic(LLLLLL)L (native)   
           (static)
        47      2       n 0     java.lang.invoke.MethodHandle::invokeBasic(LLLLL)L (native)   
        47      3       n 0     java.lang.invoke.MethodHandle::linkToSpecial(LLLLLLL)L (native)   
           (static)
        48      4       n 0     java.lang.invoke.MethodHandle::linkToStatic(L)I (native)   (static)
        48      5       n 0     java.lang.invoke.MethodHandle::invokeBasic()I (native)   
        48      6       n 0     java.lang.invoke.MethodHandle::linkToSpecial(LL)I (native)   
           (static)
[...]
        1 iteration
        69   40         n 0     java.lang.invoke.MethodHandle::linkToStatic(ILIIL)I (native)   
           (static)
[...]
Square(i) = 1
        78   48         n 0     java.lang.invoke.MethodHandle::linkToStatic(ILIJL)I (native)   
(static)
        79   49         n 0     java.lang.invoke.MethodHandle::invokeBasic(ILIJ)I (native)   
[...]
        86   54         n 0     java.lang.invoke.MethodHandle::invokeBasic(J)L (native)   
        87   55         n 0     java.lang.invoke.MethodHandle::linkToSpecial(LJL)L (native)   
(static)
Time taken= 8962738
--------------------------------
2 iteration
Square(i) = 4
Time taken= 26759
--------------------------------

10 iteration
Square(i) = 100
Time taken= 26492
--------------------------------

好像输出结果跟只用解释时并没有什么区别。根据 Oracle 的文档,这是因为只有禁用 TieredCompilation-XX:CompileThreshold 才会生效:

$ java -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler \
-XX:-TieredCompilation -XX:CompileThreshold=5 Demo
124     1       n       java.lang.invoke.MethodHandle::linkToStatic(LLLLLL)L (native)   (static)
127     2       n       java.lang.invoke.MethodHandle::invokeBasic(LLLLL)L (native)   
[...]
1 iteration
        187   40        n       java.lang.invoke.MethodHandle::linkToStatic(ILIIL)I (native)   (static)
[...]
(native)   (static)
        212   54        n       java.lang.invoke.MethodHandle::invokeBasic(J)L (native)   
        212   55        n       java.lang.invoke.MethodHandle::linkToSpecial(LJL)L (native)   (static)
Time taken= 12337415
[...]
--------------------------------
4 iteration
Square(i) = 16
Time taken= 37183
--------------------------------
5 iteration
        214   56        b       Demo::<init> (5 bytes)
        215   57        b       Demo::square (16 bytes)
Square(i) = 25
Time taken= 983002
--------------------------------
6 iteration
Square(i) = 36
Time taken= 81589
[...]
10 iteration
Square(i) = 100
Time taken= 52393

可以看到在第五次迭代之后,代码片段被 JIT 编译了:

--------------------------------
5 iteration
        214   56        b       Demo::<init> (5 bytes)
        215   57        b       Demo::square (16 bytes)
Square(i) = 25
Time taken= 983002
--------------------------------

可以看到,与 square() 方法一起,构造方法也被 JIT 编译了。在 for 循环中调用 square() 之前要先构造 Demo 实例,所以构造方法的解释次数同样达到 JIT 编译阈值。这个例子说明了在解释发生之后何时 JIT 会介入。

要查看编译后的代码,需要使用 -XX:+PrintAssembly 标志,该标志仅在库路径中有反汇编器时才起作用。对于 OpenJDK,使用 hsdis 作为反汇编器。下载合适版本的反汇编程序库,在本例中是 hsdis-amd64.so,并将其放在 Java_HOME/lib/server 目录下。使用时还需要在 -XX:+PrintAssembly 之前增加 -XX:+UnlockDiagnosticVMOptions 选项。否则,JVM 会给你一个警告。

完整命令如下:

$ java -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler \ -XX:-TieredCompilation -XX:CompileThreshold=5 -XX:+UnlockDiagnosticVMOptions \ -XX:+PrintAssembly Demo
[...]
5 iteration
        178   56        b       Demo::<init> (5 bytes)
Compiled method (c2)    178   56                Demo::<init> (5 bytes)
 total in heap  [0x00007fd4d08dad10,0x00007fd4d08dafe0] = 720
 relocation     [0x00007fd4d08dae88,0x00007fd4d08daea0] = 24
[...]
 handler table  [0x00007fd4d08dafc8,0x00007fd4d08dafe0] = 24
[...]
 dependencies   [0x00007fd4d08db3c0,0x00007fd4d08db3c8] = 8
 handler table  [0x00007fd4d08db3c8,0x00007fd4d08db3f8] = 48
----------------------------------------------------------------------
Demo.square(I)I  [0x00007fd4d08db1c0, 0x00007fd4d08db2b8]  248 bytes
[Entry Point]
[Constants]
  # {method} {0x00007fd4b841f4b0} 'square' '(I)I' in 'Demo'
  # this:       rsi:rsi   = 'Demo'
  # parm0:      rdx     = int
  #             [sp+0x20]  (sp of caller)
[...]
[Stub Code]
  0x00007fd4d08db280: movabs $0x0,%rbx          ;   {no_reloc}
  0x00007fd4d08db28a: jmpq   0x00007fd4d08db28a  ;   {runtime_call}
  0x00007fd4d08db28f: movabs $0x0,%rbx          ;   {static_stub}
  0x00007fd4d08db299: jmpq   0x00007fd4d08db299  ;   {runtime_call}
[Exception Handler]
  0x00007fd4d08db29e: jmpq   0x00007fd4d08bb880  ;   {runtime_call ExceptionBlob}
[Deopt Handler Code]
  0x00007fd4d08db2a3: callq  0x00007fd4d08db2a8
  0x00007fd4d08db2a8: subq   $0x5,(%rsp)
  0x00007fd4d08db2ad: jmpq   0x00007fd4d08a01a0  ;   {runtime_call DeoptimizationBlob}
  0x00007fd4d08db2b2: hlt    
  0x00007fd4d08db2b3: hlt    
  0x00007fd4d08db2b4: hlt    
  0x00007fd4d08db2b5: hlt    
  0x00007fd4d08db2b6: hlt    
  0x00007fd4d08db2b7: hlt    
ImmutableOopMap{rbp=NarrowOop }pc offsets: 96
ImmutableOopMap{}pc offsets: 112
ImmutableOopMap{rbp=Oop }pc offsets: 148 Square(i) = 25
Time taken= 2567698
--------------------------------
6 iteration
Square(i) = 36
Time taken= 76752
[...]
--------------------------------
10 iteration
Square(i) = 100
Time taken= 52888

我只截取了输出中与 Demo.java 相关的部分。

现在再来看看 AOT 编译。它是在 JDK9 中引入的特性。AOT 是用于生成 .so 这样的库文件的静态编译器。用 AOT 可以将指定的类编译成 .so 库。这个库可以直接执行,而不用解释或 JIT 编译。如果 JVM 没有检测到 AOT 编译的代码,它会进行常规的解释和 JIT 编译。

使用 AOT 编译的命令如下:

$ jaotc --output=libDemo.so Demo.class

用下面的命令来查看共享库的符号表:

$ nm libDemo.so

要使用生成的 .so 库,使用 -XX:+UnlockExperimentalVMOptions-XX:AOTLibrary

$ java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libDemo.so Demo
1 iteration
Square(i) = 1
Time taken= 7831139
--------------------------------
2 iteration
Square(i) = 4
Time taken= 36619
[...]
10 iteration
Square(i) = 100
Time taken= 42085

从输出上看,跟完全用解释的情况没有区别。为了确认 AOT 发挥了作用,使用 -XX:+PrintAOT

$ java -XX:+UnlockExperimentalVMOptions -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo
         28        1         loaded        ./libDemo.so  aot library
         80        1         aot[ 1]   Demo.main([Ljava/lang/String;)V
         80        2         aot[ 1]   Demo.square(I)I
         80        3         aot[ 1]   Demo.<init>()V
1 iteration
Square(i) = 1
Time taken= 7252921
--------------------------------
2 iteration
Square(i) = 4
Time taken= 57443
[...]
10 iteration
Square(i) = 100
Time taken= 53586

要确认没有发生 JIT 编译,用如下命令:

$ java -XX:+UnlockExperimentalVMOptions -Xbatch -XX:+PrintCompilation \ -XX:CompileCommandFile=hotspot_compiler -XX:-TieredCompilation \ -XX:CompileThreshold=3 -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo
         19        1         loaded        ./libDemo.so  aot library
         77        1         aot[ 1]   Demo.square(I)I
         77        2         aot[ 1]   Demo.main([Ljava/lang/String;)V
         77        3         aot[ 1]   Demo.<init>()V
         77        2         aot[ 1]   Demo.main([Ljava/lang/String;)V   made not entrant
[...]
4 iteration
Square(i) = 16
Time taken= 43366
[...]
10 iteration
Square(i) = 100
Time taken= 59554

需要特别注意的是,修改被 AOT 编译了的源代码后,一定要重新生成 .so 库文件。否则,过时的的 AOT 编译库文件不会起作用。例如,修改 square() 方法,使其计算立方值:

//Demo.java
public class Demo {

    public int square(int i) throws Exception {
        return(i*i*i);
    }

    public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 10; i++) {
          System.out.println("" + Integer.valueOf(i)+" iteration");
          long start = System.nanoTime();
          int r= new Demo().square(i);
          System.out.println("Square(i) = " + r);
          long end = System.nanoTime();
          System.out.println("Time taken= " + (end-start));
          System.out.println("--------------------------------");
        }
    }
}

重新编译 Demo.java

$ java Demo.java

但不重新生成 libDemo.so。使用下面命令运行 Demo

$ java -XX:+UnlockExperimentalVMOptions -Xbatch -XX:+PrintCompilation -XX:CompileCommandFile=hotspot_compiler -XX:-TieredCompilation -XX:CompileThreshold=3 -XX:AOTLibrary=./libDemo.so -XX:+PrintAOT Demo
         20        1         loaded        ./libDemo.so  aot library
         74        1         n           java.lang.invoke.MethodHandle::linkToStatic(LLLLLL)L (native)   (static)
2 iteration
sqrt(i) = 8
Time taken= 43838
--------------------------------
3 iteration
        137   56        b            Demo::<init> (5 bytes)
        138   57        b            Demo::square (6 bytes)
sqrt(i) = 27
Time taken= 534649
--------------------------------
4 iteration
sqrt(i) = 64
Time taken= 51916
[...]
10 iteration
sqrt(i) = 1000
Time taken= 47132

可以看到,虽然旧版本的 libDemo.so 被加载了,但 JVM 检测出它已经过时了。每次生成 .class 文件时,都会在类文件中添加一个指纹,并在 AOT 库中保存该指纹。修改源代码后类指纹与旧的 AOT 库中的指纹不匹配了,所以没有执行 AOT 编译生成的原生机器码。从输出可以看出,现在实际上是 JIT 在起作用(注意 -XX:CompileThreshold 被设置为了 3)。

AOT 和 JIT 之间的权衡

如果你的目标是减少 JVM 的预热时间,请使用 AOT,这可以减少运行时负担。问题是 AOT 没有足够的数据来决定哪段代码需要预编译为原生代码。相比之下,JIT 在运行时起作用,却对预热时间有一定的影响。然而,它将有足够的分析数据来更高效地编译和反编译代码。

(题图:MJ/ed3e6e15-56c7-4c1d-aff1-84a225faeeeb)


via: https://opensource.com/article/22/8/interpret-compile-java

作者:Jayashree Huttanagoudar 选题:lkxed 译者:toknow-gh 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

Arm 收购了树莓派公司的少量股份,以免投向 RISC-V

Arm CPU 已应用于所有树莓派单板计算机。双方的合作早在树莓派上市销售之前就开始了。最初的树莓派主板采用单核 Arm CPU,运行频率为 700 MHz。Arm 持有树莓派公司的少量股权代表了将来树莓派会继续使用 Arm CPU。随着 RISC-V CPU 的兴起,它在各种设备上出现,但在可预见的未来,我们将不会看到基于 RISC-V 的树莓派。

消息来源:Tom's Hardware
老王点评:会有使用 RISC-V 的、更便宜的开源单板计算机出现的。

解散 50 年后,披头士乐队发布了最后一首歌曲《Now And Then》

在披头士乐队解散五十年之后,它的四名成员合作发布了歌曲《Now And Then》。这首歌最初是以练习磁带的形式录制的。由于披头士乐队的两名成员约翰·列侬和乔治·哈里森已经先后去世,技术团队使用数字技术完成了新的版本。技术团队通过机器学习技术从模拟录音中分离出单个人或乐器的声音,生成了他们的声音和乐器声。两名在世的乐队成员,81 岁的保罗·麦卡特尼和 83 岁的林戈·斯塔尔分别录制了他们的新版本。这首歌在 YouTube 官方频道上 24 小时内的播放量已经超过 500 万次。

消息来源:NBC
老王点评:或许,这可能不会是披头士乐队的最后一首歌,新的 AI 技术可能能为我们复活那些过世的艺术家。

Mozilla 敦促开发者着手开发安卓扩展程序

早在 2019 年,Mozilla 就一直在考虑提供安卓扩展,但人们对其安全性存在顾虑。但即使存在安全风险,浏览器的可扩展性也是开放网络的显著特征之一,与电视等被动显示技术不同,浏览器可以让用户主动参与内容的处理和展示。2021 年 1 月,Mozilla 为安卓上的 Firefox 上推出过一组有限的扩展。现在,Mozilla 最终计划在 Firefox 120 版本之后,在安卓平台上为 Firefox 提供浏览器扩展(也称附加组件),预计当 12 月开放可用性时,将拥有至少 200 多个新的 Firefox 安卓扩展。本周,Mozilla 敦促开发人员评估他们的扩展代码,它预计“用户将对探索定制 Firefox 安卓版的各种新方法产生浓厚兴趣”。除了 Firefox 之外,Yandex 手机浏览器于 2016 年在安卓平台上就增加了对扩展的支持,Kiwi 等其他基于安卓的浏览器也是如此。而苹果公司于 2021 年 9 月就在 iOS 15 中推出了对 Safari 扩展程序的支持。

消息来源:The Register
老王点评:虽然不够早,但是终究是维护开放网络的重要努力。但是 Chrome 呢?

就在上周末,10 月 29 日的成都,LLUG 成都场成功在武侯区菁蓉汇举办。

本次活动由 Linux 中国和龙蜥社区(OpenAnolis)联合主办,异步图书、COSCON 中国开源年会提供了支持。本次活动主要由三位嘉宾共同线上线下分享为主,并辅以线下交流沟通,帮助大家在成都本地找到热爱 Linux、 热爱技术的小伙伴们。

Linux 中国的老朋友,成都不周山文化发展有限公司 CEO 孙康先生为参会者分享了他自己从 Linux 从业者,到走上技术从业,再到如今创业的经历,并深刻的剖析了作为技术从业者想要创业需要关注的事情。

老王则通过远程的为现场参会的同学们带来了他的分享:《高效开源(个人篇)》,帮助参会的同学们了解开源、学习开源。

Bestony 为现场的同学们分享了自己的大模型的开发经验,帮助参会同学们理解大模型的原理、当下的开发者们如何使用和迭代自己对于大模型的使用,提升自己的能力。

PPT及视频下载

LLUG 的创办希望帮助 Linux 社区当中的每一个人都可以充分的交流经验和心得,所以我们也将本次活动的视频以及演示文稿开放出来,供大家查看。视频托管在 Bilibili,PPT 文稿则托管在 Github 的 Linux-CN/LLUG-Shares 仓库中,供大家下载。

本次活动的 PPT 已经上传至 GitHub ,方便大家下载,视频也以上传至 Bilibili 和 Linux 中国视频号,方便大家收看。

类型活动主题主讲人PPT在线视频
主题演讲《从结识 Linux 到创业 — 我的 Linux 历程》孙康下载地址Bilibili
主题演讲《高效开源(个人篇)》wxy下载地址Bilibili
主题演讲《大模型应用开发经验分享》bestony下载地址Bilibili

致谢

本次活动的举办,得到了中国开源年会提供的线下场地支持,让我们在成都可以线下畅聊,交接技术和经验。同时,也要感谢异步图书提供的图书支持,这些高质量的图书为参会者们提供了丰富的知识,为大家带来了新知输入。

感谢大家的支持,才能让本次活动成功举办!

11 月杭州见

11 月的 LLUG 即将来到杭州~如果你感兴趣做分享,或是有更多的建议给到我们,可以扫描下方二维码,申报议题或提交建议。

(题图:MJ/55a2abbd-d5cc-499d-8fa0-57c1797aaec1)

“他们基本上是用 Emacs 作为自己的操作系统,再配上一个自定义的 LISP 脚本来收取邮件” —— 那能有什么问题呢?

本周的故事,故事的主角我们给他起名字 “Declan”,他在 1990 年和 2000 年期间,为一所大学的计算机科学系提供 IT 支持服务。

Declan 这样介绍他的工作:“我的职责多样,从基本的桌面支持,到维护院系网站,有时候还需要开发一些学者们想出来的某个什么系统。”

Declan 还补充说道,“尽管这个院系名字中带有 ‘计算机’ 这个词,但你会惊讶地发现在这个团队中各个教职工对计算机的熟练程度差异如此之大。有些聪明人用非常 ‘有趣’ 的方式使用电脑,当你步入一个教授的办公室协助‘解决他的电子邮件问题’时,你绝对会对你发现的东西感到惊讶。”

一个典型的例子是某位教授,他基本上是以 Emacs 作为其操作系统,而他的邮件客户端则是他自己用 LISP 编写的一个脚本。至于他的邮件为何无法收发,这是另一个故事了。

今天我们要讲的故事,跟 Declan 的部分用户之间发生的冲突有关。他们作为计算机科学家,对 IT 团队的存在感到不满,他们认为用在 Declan 和他的同事身上的投资,可以用于更重要的地方。对于这种观点,其中一部分人并不甘于默默背锅。

“有一次,一位讲话特别直言不讳的学者在全系会议上站出来,当着 400 名员工的面严厉批评 IT 人员,声称他不仅不需要 IT 支持人员,而且每当他提交支持申请时,我们总是无视他,” Declan 回忆道。

IT 部门的负责人因此要求他的团队去调查是否存在他所说的问题。于是,Declan 和他的团队请求那位愤怒的学者再次提交问题申请以重现问题。

学者依照他们的请求提交了申请。然而,他们却并未收到任何申请单。

接下来的步骤,则是对服务器日志的检查。

经过搜索,结果显露出来。这位学者的确提交了一张申请单,甚至还提交过几张其他的。

然而,它们都被发送到了以 “heldesk@” 开头的邮件地址。

而并非正确的包含 “p” 字母的 “helpdesk@”。

这位学者的邮件客户端记住了这个错误的地址,并且在他每次向他觉得不应存在的团队寻求帮助时,都会自动填入这个地址。

这个结果无疑是对学术严谨性的一种讽刺。

Declan 说:“这位学者被告知了他的错误,但他还是一本正经地表示,既然他的胳膊受伤,不能期待他打字完全准确,所以整个问题都不是他的责任,而并没有因为指责我们浪费金钱而道歉。”

几年前,我们有位员工手受伤了,然而他却惊讶地发现就算仅用中指打字也比想象中容易。如果 Declan 希望让那位愤怒的学者看看,我们愿意提供一个示例。

然而我们有些离题了。Declan 提到,这件事也带来了一个积极的转机,因为在那次事件发生后,计算机科学系的系主任开始“更倾向于站在 IT 人员这边,于是这场风波并非全然就是一场失败”。

你有没有过这样的经历,即与一个号称专家的人一起工作,但结果却发现他远非其言?如果有,你可以发表评论讲一下你的经历。

(题图:MJ/e3f2ea48-bd9b-4952-96c3-5963ba6378fc)


via: https://www.theregister.com/2023/11/03/on_call/

作者:Simon Sharwood 译者:ChatGPT 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出

想在 Ubuntu 上使用最新、最好的 LibreOffice?这里有一个简单的方法。

LibreOffice 已预装在 Ubuntu 中。

不过,如果你选择了最小化的 Ubuntu 安装,或者卸载它并安装了其他办公套件,你可以使用此命令轻松安装:

sudo apt install libreoffice

这没问题。但 Ubuntu 仓库提供的 LibreOffice 版本可能不是最新的。

如果你听说有新的 LibreOffice 版本发布,很可能你不会获得该新版本。这是因为 Ubuntu 将其保持在稳定版本上。

这对大多数用户来说都很好。但是,如果你不是“大多数用户”,并且你想在 Ubuntu 中获取最新的 LibreOffice,那么你完全可以这样做。

有两种方法可以做到这一点:

  • 使用官方 PPA(推荐)
  • 从 LibreOffice 下载 deb 文件

让我们来看看。

方法 1:通过官方 PPA 安装最新的 LibreOffice(推荐)

你可以使用官方 “LibreOffice Fresh” PPA 在基于 Ubuntu 的发行版上安装 LibreOffice 的最新稳定版本。

PPA 提供了 LibreOffice 的最新稳定版本,而不是开发版本。因此,这使其成为在 Ubuntu 上获取较新 LibreOffice 版本的理想选择。

你甚至不需要使用此方法卸载以前的版本。它将把现有的 LibreOffice 更新到新版本。

sudo add-apt-repository ppa:libreoffice/ppa
sudo apt update
sudo apt install libreoffice

由于你要添加 PPA,因此你还将获得以这种方式安装的新版本的更新。

方法 2:从网站获取二进制文件(如果需要)

你可以随时前往 LibreOfiice 网站的下载页面 下载最新版本的 deb 文件。你还会看到下载较旧但 LTS 稳定版本的选项。

我相信你已经 知道如何从 deb 文件安装应用。右键单击 deb 文件,选择使用软件中心打开它。进入软件中心后,你可以单击安装按钮进行安装。

结论

第二种方法的缺点是,如果有更新,你必须再次下载 deb 文件,删除以前的 LibreOffice 版本,然后使用新下载的 deb 文件安装新版本。

相比之下,PPA 会随着系统更新而自动更新。这就是我推荐 PPA 的原因,特别是当它由 LibreOffice 团队自己维护时。

顺便说一句,这里有一些 充分利用 LibreOffice 的技巧

提高 LibreOffice 生产力的技巧

我希望这个快速技巧可以帮助你在基于 Ubuntu 的发行版上获取最新的 LibreOffice。如果你有疑问,请告诉我。


via: https://itsfoss.com/install-libreoffice-ubuntu/

作者:Abhishek Prakash 选题:lujun9972 译者:geekpi 校对:wxy

本文由 LCTT 原创编译,Linux中国 荣誉推出