分类 技术 下的文章

概述你的计算机如何引导和启动一个像 FreeDOS 这样的简单操作系统。

 title=

在使用 DOS 计算机的过程中,我很欣赏的一点是,引导过程相对容易理解。在 DOS 中没有太多的变动组件。而今天,我想和大家分享一下电脑是如何引导和启动像 FreeDOS 这样的简单操作系统的概况。

初始引导

当你打开计算机的电源时,系统会进行一些自我检查,如验证内存和其他组件。这被称为 开机自检 Power On Self Test (POST)。POST 之后,计算机使用一个硬编码指令,告诉它在哪里找到加载操作系统的指令。这就是“ 引导加载程序 boot loader ”,通常它将试图找到硬盘上的 主引导记录 Master Boot Record (MBR)。然后,MBR 加载主操作系统,在这里就是 FreeDOS。

这个定位一个信息以便计算机能够加载操作系统的下一个部分的过程被称为“ 引导 bootstrapping ”,来自于“ 通过你自己的努力振作起来 picking yourself up by your bootstraps ”的古老说法。正是从这个用法中,我们采用了“ 引导 boot ”一词来表示启动你的计算机。

内核

当计算机加载 FreeDOS 内核时,内核所做的第一件事就是识别用户所表示要使用的任何参数。它被保存在一个叫做 FDCONFIG.SYS 的文件中,与内核保存在同一个根目录下。如果 FDCONFIG.SYS 不存在,那么 FreeDOS 的内核就会寻找一个叫做 CONFIG.SYS 的替代文件。

如果你在 20 世纪 80 年代或 90 年代使用过 DOS,你可能对 CONFIG.SYS 文件很熟悉。从 1999 年起,FreeDOS 首先寻找 FDCONFIG.SYS,以防你的 DOS 系统与其他 DOS(如 MS-DOS)做了 双启动。请注意,MS-DOS 只使用 CONFIG.SYS 文件。因此,如果你用同一个硬盘同时启动 FreeDOS 和 MS-DOS,MS-DOS 使用 CONFIG.SYS 来配置自己,而 FreeDOS 则使用 FDCONFIG.SYS。这样一来,双方都可以使用自己的配置。

FDCONFIG.SYS 可以包含一些配置设置,其中之一是 SHELL=SHELLHIGH=。任何一个都会指示内核加载这个程序作为用户的交互式 shell。

如果 FDCONFIG.SYSCONFIG.SYS 都不存在,那么内核就会假定几个默认值,包括在哪里找到 shell。如果你在启动 FreeDOS 系统时看到 “Bad or missing Command Interpreter” 的信息,这意味着 SHELL=SHELLHIGH= 指向了一个在你系统中不存在的 shell 程序。

 title=

你可以通过查看 SHELL=SHELLHIGH= 行来调试这个问题。如果做不到这一点,请确保你在 FreeDOS 系统的根目录下有一个名为 COMMAND.COM 的程序。它就是 shell,我接下来会讲到它。

shell

在 DOS 系统中,“shell” 一词通常是指一个命令行解释器:一个交互式程序,它从用户那里读取指令,然后执行它们。在这里,FreeDOS 的 shell 与 Linux 的 Bash shell 相似。

除非你用 SHELL=SHELLHIGH= 要求内核加载一个不同的 shell,否则 DOS 上的标准命令行 shell 被称为 COMMAND.COM。当 COMMAND.COM 启动时,它也寻找一个文件来配置自己。默认情况下,COMMAND.COM 会在根目录下寻找一个名为 AUTOEXEC.BAT 的文件。AUTOEXEC.BAT 是一个“批处理文件”,它包含一组启动时运行的指令,大致类似于 Linux 上 Bash 启动时读取的 ~/.bashrc “资源文件”。

你可以在 FDCONFIG.SYS 文件中用 SHELL=SHELLHIGH= 改变 shell 以及 shell 的启动文件。FreeDOS 1.3 RC4 安装程序将系统设置为读取 FDAUTO.BAT 而不是 AUTOEXEC.BAT。这与内核读取另一个配置文件的原因相同;你可以在硬盘上用另一个 DOS 双启动 FreeDOS。FreeDOS 将使用 FDAUTO.BAT 而 MS-DOS 将使用 AUTOEXEC.BAT

如果没有像 AUTOEXEC.BAT 这样的启动文件,shell 将简单地提示用户输入日期和时间。

 title=

就是这些了。当 FreeDOS 加载了内核,而内核也加载了 shell,FreeDOS 就准备好让用户输入命令了。

 title=


via: https://opensource.com/article/21/6/freedos-boots

作者:Jim Hall 选题:lujun9972 译者:geekpi 校对:wxy

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

在 Linux 系统上管理系统资源的推荐工具是 cgroups。虽然在可以调整的限制方面(CPU、内存、磁盘 I/O、网络等)非常强大,但配置 cgroups 并不简单。nice) 命令从 1973 年起就可以使用了。但它只是调整在一个处理器上竞争时间的进程之间的调度优先级。nice 命令不会限制一个进程在单位时间内所能消耗的 CPU 周期的百分比。cpulimit 命令提供了两个世界的最佳方案。它限制了一个进程在每单位时间内可以分配的 CPU 周期的百分比,而且相对容易调用。

cpulimit 命令主要对长期运行的和 CPU 密集型的进程有用。编译软件和转换视频是长期运行的进程的常见例子,它们可以使计算机的 CPU 使用率达到最大。限制这类进程的 CPU 使用率将释放出处理器时间,供计算机上可能运行的其他任务使用。限制 CPU 密集型进程也将减少功耗及热输出,并可能减少系统的风扇噪音。限制一个进程的 CPU 使用率的代价是,它需要更多的时间来完成运行。

安装 cpulimit

cpulimit 命令在默认的 Fedora Linux 仓库中可用。运行下面的命令,在 Fedora Linux 系统上安装 cpulimit

$ sudo dnf install cpulimit

查看 cpulimit 的文档

cpulimit 软件包并没有附带的手册页。使用下面的命令来查看 cpulimit 的内置文档。输出结果在下面提供。但你可能需要在你自己的系统上运行该命令,以防止自本文编写以来选项发生变化。

$ cpulimit --help
Usage: cpulimit [OPTIONS…] TARGET
   OPTIONS
      -l, --limit=N percentage of cpu allowed from 0 to 800 (required)
      -v, --verbose show control statistics
      -z, --lazy exit if there is no target process, or if it dies
      -i, --include-children limit also the children processes
      -h, --help display this help and exit
   TARGET must be exactly one of these:
      -p, --pid=N pid of the process (implies -z)
      -e, --exe=FILE name of the executable program file or path name
      COMMAND [ARGS] run this command and limit it (implies -z)

演示

为了演示 cpulimit 命令的使用方式,下面提供了一个精心设计的、计算量很大的 Python 脚本。该脚本首先在没有限制的情况下运行,然后在限制为 50% 的情况下运行。它计算的是第 42 个 斐波那契数 的值。该脚本在这两种情况下都作为 time 命令的子进程运行,以显示计算答案所需的总时间。

$ /bin/time -f '(computed in %e seconds)' /bin/python -c 'f = lambda n: n if n<2 else f(n-1)+f(n-2); print(f(42), end=" ")'
267914296 (computed in 51.80 seconds)
$ /bin/cpulimit -i -l 50 /bin/time -f '(computed in %e seconds)' /bin/python -c 'f = lambda n: n if n<2 else f(n-1)+f(n-2); print(f(42), end=" ")'
267914296 (computed in 127.38 seconds)

当运行第一个版本的命令时,你可能会听到电脑上的 CPU 风扇转动起来。但在运行第二个版本时,你应该不会。第一个版本的命令不受 CPU 的限制,但它不应该导致你的电脑陷入瘫痪。它是以这样一种方式编写的:它最多只能使用一个 CPU 核心。大多数现代 PC 都有多个 CPU 核心,当其中一个 CPU 100% 繁忙时,可以毫无困难地同时运行其他任务。为了验证第一条命令是否使你的一个处理器达到最大,在一个单独的终端窗口中运行 top 命令并按下 1 键。要退出 top 命令可以按 Q 键。

设置高于 100% 的限制只对能够进行 任务并行化 的程序有意义。对于这样的程序,高于 100% 的增量代表一个 CPU 的全部利用率(200%=2 个CPU,300%=3 个CPU,等等)。

注意,在上面的例子中,-i 选项已经传递给 cpulimit 命令。这是必要的,因为要限制的命令不是 cpulimit 命令的直接子进程。相反,它是 time 命令的一个子进程,而后者又是 cpulimit 命令的一个子进程。如果没有 -i 选项,cpulimit 将只限制 time 命令。

最后说明

如果你想限制一个从桌面图标启动的图形程序,请将该程序的 .desktop 文件(通常位于 /usr/share/applications 目录下)复制到你的 ~/.local/share/applications 目录下,并相应修改 Exec 行。然后运行下面的命令来应用这些变化:

$ update-desktop-database ~/.local/share/applications

via: https://fedoramagazine.org/use-cpulimit-to-free-up-your-cpu/

作者:Gregory Bartholomew 选题:lujun9972 译者:geekpi 校对:wxy

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

一旦你理解了一般原则,C++ 类成员函数指针不再那么令人生畏。

 title=

如果你正在寻找性能、复杂性或许多可能的解决方法来解决问题,那么在涉及到极端的情况下,C++ 总是一个很好的选择。当然,功能通常伴随着复杂性,但是一些 C++ 的特性几乎难以分辨。根据我的观点,C++ 的 类成员函数指针 也许是我接触过的最复杂的表达式,但是我会先从一些较简单的开始。

文章中的例子可以在我的 Github 仓库 里找到。

C 语言:函数指针

让我们先从一些基础开始:假设你有一个函数接收两个整数作为参数返回一个整数:

int sum(int a, int b) {
    return a+b;
}

在纯 C 语言中,你可以创建一个指向这个函数的指针,将其分配给你的 sum(...) 函数,通过解引用来调用它。函数的签名(参数、返回类型)必须符合指针的签名。除此之外,一个函数指针表现和普通的指针相同:

int (*funcPtrOne)(int, int);

funcPtrOne = &sum;

int resultOne = funcPtrOne(2, 5);

如果你使用指针作为参数并返回一个指针,这会显得很丑陋:

int *next(int *arrayOfInt){
    return ++arrayOfInt;
}

int *(*funcPtrTwo)(int *intPtr);

funcPtrTwo = &next;

int resultTwo = *funcPtrTwo(&array[0]);

C 语言中的函数指针存储着子程序的地址。

指向类成员函数的指针

让我们来进入 C++:好消息是你也许不需要使用类成员函数指针,除非在一个特别罕见的情况下,比如说接下来的例子。首先,你已经知道定义一个类和其中一个成员函数:

class MyClass
{
public:

    int sum(int a, int b) {
        return a+b;
    }

};

1、定义一个指针指向某一个类中一个成员函数

声明一个指针指向 MyClass 类成员函数。在此时,你并不知道想调用的具体函数。你仅仅声明了一个指向 MyClass 类中任意成员函数的指针。当然,签名(参数、返回值类型)需要匹配你接下想要调用的 sum(...) 函数:

int (MyClass::*methodPtrOne)(int, int);

2、赋值给一个具体的函数

为了和 C 语言(或者 静态成员函数#Static_method))对比,类成员函数指针不需要指向绝对地址。在 C++ 中,每一个类中都有一个虚拟函数表(vtable)用来储存每个成员函数的地址偏移量。一个类成员函数指针指向 vtable 中的某个条目,因此它也只存储偏移值。这样的原则使得 多态 变得可行。

因为 sum(...) 函数的签名和你的指针声明匹配,你可以赋值签名给它:

methodPtrOne = &MyClass::sum;

3、调用成员函数

如果你想使用指针调用一个类成员函,你必须提供一个类的实例:

MyClass clsInstance;
int result = (clsInstance.*methodPtrOne)(2,3);

你可以使用 . 操作符来访问,使用 * 对指针解引用,通过提供两个整数作为调用函数时的参数。这是丑陋的,对吧?但是你可以进一步应用。

在类内使用类成员函数指针

假设你正在创建一个带有后端和前端的 客户端/服务器 原理架构的应用程序。你现在并不需要关心后端,相反的,你将基于 C++ 类的前端。前端依赖于后端提供的数据完成初始化,所以你需要一个额外的初始化机制。同时,你希望通用地实现此机制,以便将来可以使用其他初始化函数(可能是动态的)来拓展你的前端。

首先定义一个数据类型用来存储初始化函数(init)的指针,同时描述何时应调用此函数的信息(ticks):

template<typename T>
struct DynamicInitCommand {
    void (T::*init)();     // 指向额外的初始化函数
    unsigned int ticks;    // 在 init() 调用后 ticks 的数量
};

下面一个 Frontend 类示例代码:

class  Frontend
{
public:

    Frontend(){
        DynamicInitCommand<Frontend> init1, init2, init3;

        init1 = { &Frontend::dynamicInit1, 5};
        init2 = { &Frontend::dynamicInit2, 10};
        init3 = { &Frontend::dynamicInit3, 15};

        m_dynamicInit.push_back(init1);
        m_dynamicInit.push_back(init2);
        m_dynamicInit.push_back(init3);
    }
   
    void  tick(){
        std::cout << "tick: " << ++m_ticks << std::endl;
       
        /* 检查延迟初始化 */
        std::vector<DynamicInitCommand<Frontend>>::iterator  it = m_dynamicInit.begin();

        while (it != m_dynamicInit.end()){
            if (it->ticks < m_ticks){
                 
                if(it->init)
                    ((*this).*(it->init))(); // 这里是具体调用

                it = m_dynamicInit.erase(it);

            } else {
                it++;
            }
        }
    }
   
    unsigned  int  m_ticks{0};
   
private:

    void  dynamicInit1(){
        std::cout << "dynamicInit1 called" << std::endl;
    };

    void  dynamicInit2(){
        std::cout << "dynamicInit2 called" << std::endl;
    }

    void  dynamicInit3(){
        std::cout << "dynamicInit3 called" << std::endl;
    }

    unsigned  int  m_initCnt{0};
    std::vector<DynamicInitCommand<Frontend> > m_dynamicInit;
};

Frontend 完成实例化后,tick() 函数会被后端以固定的时间时间调用。例如,你可以每 200 毫秒调用一次:

int  main(int  argc, char*  argv[]){
    Frontend frontendInstance;

    while(true){
        frontendInstance.tick(); // 仅用于模拟目的
        std::this_thread::sleep_for(std::chrono::milliseconds(200));
    }
}

Fronted 有三个额外的初始化函数,它们必须根据 m_ticks 的值来选择调用哪个。在 ticks 等于何值调用哪个初始化函数的信息存储在数组 m_dynamicInit 中。在构造函数(Frontend())中,将此信息附加到数组中,以便在 5、10 和 15 个 tick 后调用其他初始化函数。当后端调用 tick() 函数时,m_ticks 值会递增,同时遍历数组 m_dynamicInit 以检查是否必须调用初始化函数。

如果是这种情况,则必须通过引用 this 指针来取消引用成员函数指针:

((*this).*(it->init))()

总结

如果你并不熟悉类成员函数指针,它们可能会显得有些复杂。我做了很多尝试和经历了很多错误,花了一些时间来找到正确的语法。然而,一旦你理解了一般原理后,方法指针就变得不那么可怕了。

这是迄今为止我在 C++ 中发现的最复杂的语法。 你还知道更糟糕的吗? 在评论中发布你的观点!


via: https://opensource.com/article/21/2/ccc-method-pointers

作者:Stephan Avenwedde 选题:lujun9972 译者:萌新阿岩 校对:wxy

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

开发和实施云原生(容器优先)软件的检查清单。

 title=

许多年来,单体应用是实现业务需求的标准企业架构。但是,当云基础设施开始以规模和速度为业务加速,这种情况就发生了重大变化。应用架构也发生了转变,以适应云原生应用和 微服务无服务器 以及事件驱动的服务,这些服务运行在跨混合云和多云平台的不可变的基础设施上。

云原生与 Kubernetes 的联系

根据 云原生计算基金会 (CNCF) 的说法:

“云原生技术使企业能够在现代动态环境中建立和运行可扩展的应用,如公共云、私有云和混合云。容器、服务网格、微服务、不可变的基础设施和声明式 API 就是这种方法的典范。”

“这些技术使松散耦合的系统具有弹性、可管理和可观察性。与强大的自动化相结合,它们使工程师能够以最小的工作量频繁地、可预测地进行重要的改变。”

Kubernetes 这样的容器编排平台允许 DevOps 团队建立不可变的基础设施,以开发、部署和管理应用服务。现在,快速迭代的速度与业务需求相一致。构建容器以在 Kubernetes 中运行的开发人员需要一个有效的地方来完成。

云原生软件的要求

创建云原生应用架构需要哪些能力,开发人员将从中获得哪些好处?

虽然构建和架构云原生应用的方法有很多,但以下是一些需要考虑的部分:

  • 运行时: 它们更多是以容器优先或/和 Kubernetes 原生语言编写的,这意味着运行时会如 Java、Node.js、Go、Python 和 Ruby。
  • 安全: 在多云或混合云应用环境中部署和维护应用时,安全是最重要的,应该是环境的一部分。
  • 可观察性: 使用 Prometheus、Grafana 和 Kiali 等工具,这些工具可以通过提供实时指标和有关应用在云中的使用和行为的更多信息来增强可观察性。
  • 效率: 专注于极小的内存占用、更小的构件大小和快速启动时间,使应用可跨混合/多云平台移植。
  • 互操作性: 将云原生应用与能够满足上述要求的开源技术相结合,包括 Infinispan、MicroProfile、Hibernate、Kafka、Jaeger、Prometheus 等,以构建标准运行时架构。
  • DevOps/DevSecOps: 这些方法论是为持续部署到生产而设计的,与最小可行产品 (MVP) 一致,并将安全作为工具的一部分。

让云原生具体化

云原生似乎是一个抽象的术语,但回顾一下定义并像开发人员一样思考可以使其更加具体。为了使云原生应用获得成功,它们需要包括一长串定义明确的组成清单。

你是如何规划云原生应用的设计的?在评论中分享你的想法。


via: https://opensource.com/article/20/1/cloud-native-software

作者:Daniel Oh 选题:lujun9972 译者:geekpi 校对:wxy

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

它看起来像复古计算,但它是一个现代的操作系统,你可以用它来完成任务。

 title=

在整个 1980 年代和 1990 年代,我主要是一个 DOS 用户。我喜欢 DOS 提供的命令行环境,它随着每一个连续的版本变得更加强大。我甚至学会了如何用 C 语言编写自己的 DOS 程序,这样我就可以扩展 DOS 命令行,并为标准的 DOS 命令编写更强大的替代程序。我曾经试验过微软的 Windows,但如果你记得当时的 Windows 3,你就会知道它很慢,而且容易崩溃。但无论如何我更喜欢命令行,所以我坚持使用 DOS。

这一切在 1994 年发生了变化。流行的技术杂志谈到了即将到来的 Windows 版本,它将完全废除 DOS。我不想被迫使用 Windows。在我访问的 Usenet 讨论区中,其他人也有同样的感觉。所以在 1994 年 6 月 29 日,我认为如果我们想保留 DOS,我们需要自己编写。所以在 6 月 29 日,我宣布了一个小项目,这个项目后来成为 FreeDOS 项目

从那时起,我们已经发布了几个完整的 FreeDOS 发行版。我们从 1994 年到 1997 年的 alpha 系列开始,再到 1998 年到 2005 年的 beta 系列,最后在 2006 年发布了 FreeDOS 1.0 版本。从那时起,进展是缓慢但稳定的。在 1.0 之后,我们并没有真正急于发布每个新版本,因为 DOS 在 1995 年不再是一个变动的目标。

从 1.0 开始的每一个 FreeDOS 发行版都是对现代 DOS 的不断重新想象。我们已经包括了很多编译器和汇编器,供开发人员编写软件。我们还提供了许多“强大工具”,以便你可以做真正的工作。我们还提供了各种编辑器,因为每个人都有自己的最爱。

我们最近发布了 FreeDOS 1.3 RC4 发行版。从技术上讲,这是我们即将推出的 FreeDOS 1.3 发行版的候选版本,但它是一个全功能的发行版。我对 FreeDOS 1.3 RC4 的所有功能感到非常兴奋。

无需安装 FreeDOS 即可运行 FreeDOS

在我们以前所有的 FreeDOS 发行版中,我们把重点放在 安装 FreeDOS 到电脑上。但我们认识到,大多数用户实际上已经不在实际硬件上运行 FreeDOS 了。他们在 像 QEMU 或 VirtualBox 这样的虚拟机 中运行 FreeDOS。所以在 FreeDOS 1.3 RC4 中,我们改进了 “LiveCD” 环境。

通过 FreeDOS 1.3 RC4,你可以在你喜欢的虚拟机中启动 LiveCD 镜像,并立即开始使用 FreeDOS。这就是我现在运行 FreeDOS 的方式。我有一个小的虚拟硬盘镜像,我把所有的文件都放在那里,但我从 LiveCD 启动并运行 FreeDOS。

 title=

启动 FreeDOS 1.3 RC4 LiveCD (Jim Hall, CC-BY SA 4.0

安装真的很简单

如果你不想从 LiveCD 上运行 FreeDOS,你也可以在你的硬盘上安装它。我们更新了 FreeDOS 的安装程序,所以它本身并不是一个真正的“程序”,而是一个非常聪明的 DOS “批处理”文件,它可以检测到各种情况并采取适当的行动,例如在没有 FreeDOS 分区的情况下为其创建一个新的磁盘分区。

旧的 FreeDOS 发行版会提示你各种问题,甚至选择个别程序来安装。新的安装程序非常精简。它只问你几个问题就开始了,然后就自己做其他事情。在一个空的虚拟机上安装 FreeDOS 只需要几分钟时间。

 title=

安装FreeDOS 1.3 RC4 (Jim Hall, CC-BY SA 4.0

你可以从软盘安装它

不是每个人都喜欢在虚拟机中运行 FreeDOS。现在有一个复古计算社区,他们收集并精心修复经典的 PC 硬件,如 Pentium 或 486 系统。你甚至可以在那里找到一些 XT(8088)或 AT(80286)系统,它由一个专门的用户社区运营。

虽然我们认为 FreeDOS 是一个现代的 DOS,但如果我们不在旧的 PC 硬件上运行,我们就不是 “DOS” 了。因此,在 FreeDOS 1.3 中,我们包含了一个纯软盘版!这个版本可以运行在任何硬件上。这个版本应该可以在任何可以运行 FreeDOS 的硬件上运行,并且有 EGA 或更好的图形。

你在运行 286 或其他没有 CD-ROM 驱动器的经典系统吗?从这些软盘安装 FreeDOS。你是否只有一个硬盘而没有 CD 或软盘驱动器?只要把软盘的内容复制到一个临时目录,然后从那里运行安装程序。想执行“无交互外设方式”安装到不同的 DOS 目录吗?用命令行选项就可以了。

纯软盘版使用一个完全不同的安装程序,并包含一套有限的 FreeDOS 程序,它们在经典的 PC 硬件上更有用。

 title=

安装FreeDOS纯软盘版 (Jim Hall, CC-BY SA 4.0

充满了开源应用和游戏

如果 FreeDOS 是一个闭源的 DOS,它就不是一个 自由 的 DOS。我们希望每个人都能使用和研究 FreeDOS,包括其源代码。当我们计划 FreeDOS 1.3 发行版时,我们仔细检查了每个软件包中的每一个许可证,并专注于只包括 开源 程序。(在以前的 FreeDOS 发行版中,有几个程序并不完全“开源”,还有一两个程序没有包括源码,但是可以“自由使用和发布”。在这个版本中,所有的东西都是开源的,以“开源定义”作为我们的模型。)

而且,这是一个多么棒的开源应用和游戏的集合。游戏是 FreeDOS 1.3 RC4 中我最喜欢的内容。许多人使用 FreeDOS 来玩经典的 DOS 游戏,但我们想提供我们自己的开源游戏给人们玩。

你可以发现 LiveCD 中已经安装了两个游戏:Simple Senet(可以追溯到古埃及的棋盘游戏)和 Floppy Bird(Flappy Bird 游戏的一个版本)。如果你安装了 FreeDOS,你还会发现很多其他游戏可以尝试,包括 Sudoku86(一个数独游戏)、Wing(一个太空射击游戏)和 Bolitaire(单人纸牌游戏)。

 title=

玩 Floppy Bird 游戏 (Jim Hall, CC-BY SA 4.0

 title=

古老的 Senet 游戏 (Jim Hall, CC-BY SA 4.0

现在就试试 FreeDOS 1.3 RC4

你可以在 FreeDOS 的 下载 页面上找到新的 FreeDOS 1.3 RC4。要安装 FreeDOS,你需要至少 20MB 的可用磁盘空间:20MB 用来安装一个普通的 FreeDOS 系统,或者 250MB 用来安装所有,包括应用和游戏。要安装源码,你将需要高达 450MB 的可用空间。


via: https://opensource.com/article/21/6/get-started-freedos

作者:Jim Hall 选题:lujun9972 译者:geekpi 校对:wxy

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

Java 具有功能强大、多样化、可拓展、有趣的特点。这就是 Java 为什么被我们广泛使用,也是我们如何正确使用它的方式。

 title=

Java 是在 1995 年发布的,当我写这篇文章的时候,它已经 26 岁了。起初它是专有的,但在 2007 年,Java 基于 GPL 协议被开源发布了。如果想要理解是什么使得 Java 变得非常重要,你就必须理解它声称要解决的是什么样的问题,从而你就能理解它让开发者和用户受益的原因和方式。

理解 Java 解决了什么问题的最好方式就是进行软件开发,当然啦,如果不做开发,仅仅只是使用软件也会是一个很好的开始。作为一名开发人员,当你将在自己的本地计算机上运行良好的软件部署到其他计算机上运行时,一些稀奇古怪的麻烦可能就出现了,从而导致软件可能无妨正常运行。软件本应正常工作,但每个程序员都明白,一些问题总是会被忽视。当你在另一个操作系统上尝试运行该软件时,情况就变得更加复杂了。这也是为什么在每一个软件的获取页面上都会有针对不同的操作系统有对应下载按钮的原因:Windows 的、macOS 的、Linux 的、移动端的、甚至许多其他操作系统环境的下载选项。

作为一名用户,一个典型的场景是你想下载一些优秀的软件,但它却不适用于你的平台。遗憾的是这样的情况仍然发生在当下非常先进的计算机上,它们可以在计算机中运行虚拟机,通过仿真使老式视频游戏保持活力,甚至可以放在你的口袋里,但软件交付实际上相当困难。

有没有更好的办法?可能会有吧。

1、一次编码,任意环境都能跑通

令人惊讶甚至是失望的是,代码是特定于操作系统和环境的。代码需要从对人友好的高级程序设计语言编译成机器语言,即被设计可以用于让 CPU 响应的一系列二进制指令。在先进的计算机世界中,我们很难理解为什么不能仅仅只要编写代码,就能将它发送给任何一个想要运行它的平台,无需担忧它们正处在什么样的平台中。

Java 可以解决这种不协调的问题。它的代码是可以跨平台进行工作的,在任何运行它的系统上都执行相同的工作。Java 实现这一壮举的方法起初是有悖常理的。在某种程度上,Java 只与一台计算机兼容。奇怪的是,这台电脑实际上并不存在。Java 代码的目标计算机是Java 虚拟机(JVM)。这是一个由 Java 的创建者编写的程序,可用于你能想到的任何计算机设备。只要你安装了它,你运行的任何 Java 代码都会由你计算机中的这台“虚拟”计算机进行处理。Java 代码会由 JVM 执行,JVM 向你的计算机发送适当的特定于平台的指令,因此所有工作在每个操作系统和架构上都是一样的。

当然,Java 使用的方法并不是这里的真正的卖点。大多数用户和许多开发人员并不关心软件兼容性是如何实现的,只关心它是否具备兼容性。许多语言都承诺提供跨平台的功能,通常情况下,这个承诺最终都是真的,但是这个过程并不总是容易实现的。编程语言必须针对其目标平台进行编译,脚本语言需要特定于平台的解释器,而且两者都很难确保对底层系统资源的一致访问。跨平台支持变得越来越好,库可以帮助转换路径、环境变量和设置,并且一些框架(特别是 Qt)在弥补外设访问的差距方面做了很多工作。但是,Java 始终可靠地提供它的兼容性。

2、明智的代码

Java 的语法即使是在最好的方面也很无聊。如果你把所有流行的编程语言都放在一个摇滚杯中,那么你会得到 Java。通过观察 Java 编写的源代码,你或多或少会均匀地看到所有特定的编程表达方式。括号表示函数和流程控制的范围、变量在使用前被明确地声明和实例化,并且表达式具有清晰一致的结构。

我发现 Java 学习过程中通常会鼓励自学成才的程序员使用结构化程度较少的语言编写更精炼的代码。从网上学习的源代码中收集到的技术中,有许多“基本”编程经验是你无法学到的,比如以 Java 公开字段的风格进行全局变量声明、正确地预测和处理异常、使用类和函数、和许多其他的技术。从 Java 借鉴的一点小改动可以产生很大的不同。

3、脚手架和支持

流行的编程语言都有很好的支持系统,这也是使得其变成流行语言的原因。它们都有很多文档资料,有针对它们的集成开发环境或 IDE 扩展、示例代码、免费和付费培训和开发者社区。在另一方面,当你在尝试做某事遇到困难时,似乎没有任何编程语言有足够的支持。

我不能说 Java 可以摆脱这两个普遍但又相互矛盾的事实。尽管如此,我发现当我需要一个 Java 库时,我必然能为给定的任务找到多个选项。通常我不想使用一个库的原因是我不喜欢它的开发人员如何实现我需要的功能,它的许可证与我喜欢的有所不同,或者有其他琐碎的争议点。当一门语言得到大量支持时,我就会很多的选择性。我可以从许多合适的解决方案中选择一个最能满足我需求的,不论我的需求多么微不足道都能被最好得满足。

更好的是,围绕 Java 有一个健康的基础设施。像 Apache AntGradleMaven 等工具可以帮助管理构建和交付的过程。像 Sonatype Nexus 等服务帮助实现监控的安全性。SpringGrails 使 Web 开发变得更加容易,而 QuarkusEclipse Che 有助于云上的开发。

在接触 Java 语言本身时,你甚至可以选择使用什么样的版本。OpenJDK 提供经典的、官方的 Java,而 Groovy 是一种类似于脚本语言的简化方法(你可以把它比作 Python),而 Quarkus 提供了一个容器优先开发的框架。

还有很多,但现在已经足以说明 Java 是一个完整的生态了,无论你想在其中寻找什么。

此外,简单易学

事实证明,Java 对我和各行各业的许多开发人员来说是一个明智的解决方案。以下是我喜欢使用 Java 的一些原因。

你可能听说过或推断出 Java 是一种“专业”语言,只适用于笨重的政府网站,专供“真正的”开发人员使用。千万不要被 Java 25 年以来的各种名声所迷惑!它的可怕程度只有它名声的一半,这意思是,并不比其他任何语言更可怕。

编程很困难的这件事是无法回避的,它要求你基于逻辑进行思考,学习一种比母语表达方式更少的新语言,要你弄清楚如何解决困难的问题,使它们可以使用你的程序完成自动化的执行,没有语言可以避免这些问题。

然而,编程语言的学习曲线的差异令人惊讶。有些一开始很容易,但当你开始探索细节时就会变得复杂。换句话说,打印“hello world”可能只需要一行代码,但当你学习到了类和函数, 你相当于开始重新学习这门语言(或者至少是它的数据模型)。Java 从一开始就是 Java,一旦你学会了它,就可以使用它的许多技巧和便利。

简而言之: 去学习 Java 吧!它具有功能强大、多样化、可拓展、有趣的特点。为了给你提供帮助, 下载我们的 Java 备忘单, 它包含你在开发前十个项目时需要的所有基本语法。在那之后,你就不再需要它了,因为 Java 具有完美的一致性和可预测性。来享受它吧!


via: https://opensource.com/article/21/5/java

作者:Seth Kenlon 选题:lujun9972 译者:PearFL 校对:wxy

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