AI Chat 设计模式:7. 单例模式

news2024/11/15 17:59:06

本文是该系列的第七篇,采用问答式的方式展开,问题由我提出,答案由 Chat AI 作出,灰色背景的文字则主要是我的旁白和思考。

问题列表

  • Q.1 简单介绍一下单例模式
  • A.1
  • Q.2 详细说说饿汉式,并使用 c++ 举例
  • A.2
  • Q.3 好,继续说说懒汉式
  • A.3
  • Q.4 这种双重检查,有什么问题不
  • A.4
  • Q.5 单例模式,是否需要把拷贝构造函数和拷贝赋值函数也设为私有呢
  • A.5
  • Q.6 好的,总结一下上面几种单例模式写法的特点吧
  • A.6
  • Q.7 单例模式,对象内存怎么释放呢
  • A.7
  • Q.8 有什么办法,在程序结束时能主动回收单例对象占用的内存,而不是等操作系统来回收吗?
  • A.8
  • Q.9 好的,我看网上有一种,在单例类中嵌套一个垃圾回收类的写法,给我说说呗
  • A.9
  • Q.10 画一下单例模式的类图
  • A.10

Q.1 简单介绍一下单例模式

A.1

单例模式是一种设计模式,旨在确保类只能有一个实例,并提供全局访问点来获取该实例。这意味着无论在系统中的哪个位置,调用者获取到的都是同一个实例对象。

单例模式常用于需要限制实例个数的场景,例如数据库连接对象、线程池、日志管理器等。通过使用单例模式,可以确保所有的调用方都使用同一个实例,避免了资源的重复创建和重复占用。

实现单例模式的关键是将类的构造函数设为私有,这样就无法在类的外部直接实例化对象。然后,通过一个静态方法或静态属性来创建或获取唯一的实例对象。这个方法或属性在第一次调用时会判断实例是否已存在,如果不存在就创建一个新的实例,然后返回该实例。如果实例已存在,就直接返回该实例。

单例模式有几种常见的实现方式,包括懒汉式饿汉式、双重检查锁式等,每种方式都有其适用的场景和特点。在实际使用中,需要根据具体的需求和线程安全性的考虑选择适合的实现方式。

单例模式使用了一种特殊的语法结构,将构造函数变为私有。

Q.2 详细说说饿汉式,并使用 c++ 举例

A.2

饿汉式是单例模式的一种实现方式,它的核心思想是在类加载时就创建好实例对象,并在需要时直接返回该对象。因此,它是线程安全的,但可能会造成资源的浪费

下面是一个使用C++实现的饿汉式单例模式的示例代码:

class Singleton {
private:
    static Singleton* instance;  // 唯一实例的指针

    // 私有构造函数,防止外部实例化对象
    Singleton() {}

public:
    // 获取单例对象的静态方法
    static Singleton* getInstance() {
        return instance;
    }
};

// 在类外部初始化静态成员变量
Singleton* Singleton::instance = new Singleton();

int main() {
    Singleton* obj1 = Singleton::getInstance();
    Singleton* obj2 = Singleton::getInstance();

    // obj1和obj2指向同一个对象,说明单例模式生效
    if(obj1 == obj2) {
        cout << "obj1 and obj2 are the same instance" << endl;
    }
    else {
        cout << "obj1 and obj2 are different instances" << endl;
    }

    return 0;
}

在这个示例中,Singleton类中定义了一个名为instance的静态成员变量,用于存储唯一的实例对象。在类外部,我们对instance进行了初始化,即在程序启动时就创建了实例对象。getInstance()方法用于获取该实例对象。

main()函数中,通过调用getInstance()方法获取到两个对象obj1obj2。通过比较它们的指针地址,我们可以确认它们是否指向同一个对象,从而验证单例模式是否生效。

需要注意的是,饿汉式是一种线程安全的实现方式,因为实例对象在类加载时就已经创建好了,不会出现多线程下的竞争问题。但也因为在程序启动时就创建实例对象,可能会造成资源的浪费,特别是在实例对象占用大量资源或需要进行耗时操作的情况下。

关键词:启动时创建、线程安全、资源浪费

Q.3 好,继续说说懒汉式

A.3

懒汉式是单例模式的另一种常见实现方式。与饿汉式不同,懒汉式在第一次需要获取实例对象时才会进行实例化,避免了不必要的资源浪费。但懒汉式在多线程环境下需要注意线程安全性。

下面是一个使用C++实现的简单懒汉式单例模式的示例代码:

#include <iostream>
#include <mutex>

using namespace std;

class Singleton {
private:
    static Singleton* instance;  // 唯一实例的指针
    static mutex mtx;  // 互斥锁,用于线程安全

    // 私有构造函数,防止外部实例化对象
    Singleton() {}

public:
    // 获取单例对象的静态方法
    static Singleton* getInstance() {
        if (instance == nullptr) {
            lock_guard<mutex> lock(mtx);  // 加锁,确保线程安全

            // 双重检查,防止多个线程同时通过第一个if语句
            if (instance == nullptr) {
                instance = new Singleton();
            }
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;
mutex Singleton::mtx;

int main() {
    Singleton* obj1 = Singleton::getInstance();
    Singleton* obj2 = Singleton::getInstance();

    // obj1和obj2指向同一个对象,说明单例模式生效
    if (obj1 == obj2) {
        cout << "obj1 and obj2 are the same instance" << endl;
    } else {
        cout << "obj1 and obj2 are different instances" << endl;
    }

    return 0;
}

在这个示例中,Singleton类中定义了一个名为instance的静态成员变量,用于存储唯一的实例对象。同时,还定义了一个静态的互斥锁mtx,用于在线程安全的环境下保护实例的创建过程。

getInstance()方法中,首先判断instance是否为nullptr,如果是,表示还没有创建实例对象,此时通过加锁的方式避免多线程同时创建实例。在加锁后,再次检查instance是否为nullptr,这是为了避免多个线程都通过了第一个检查,争夺锁之后再次创建实例。只有在第二次检查通过时,才实例化对象。

通过使用互斥锁,可以确保懒汉式在多线程环境下的线程安全性。只有当第一个线程创建好实例对象并释放锁之后,后续的线程才能获取到创建好的对象。这样可以避免多个线程同时创建多个实例对象的问题。

需要注意的是,懒汉式在第一次获取实例对象时才进行实例化,避免了不必要的资源消耗。但由于加锁机制的存在,会有一定的性能开销。此外,在高并发情况下,可能会出现多个线程同时通过第一个if语句的情况,虽然通过双重检查可以解决这个问题,但在某些特定的情况下,可能还需要采用其他的线程安全机制来保证单例模式的正确性。

为什么是双重检查呢?我们假设没有第一个 if 条件,那么就相当于锁了getInstance 这整个方法,当多个线程调用时,效率就很低,且如果类实例已经创建了,就只是只读访问,完全没必要加锁了。

先说说 instance == nullptr 这个条件,如果不成立,则类对象一定以及创建了,如果成立,则对象一定没创建吗?答案是否定的。

我们先看第一个 if,如果不成立,则对象已经被创建了,直接返回即可。如果成立,我们假设现在有两个线程,现在线程1通过了第一个 if 条件,刚要执行 instance = new Singleton() 的时候,却突然切到线程 2 了,此时线程2中第一个条件也会成立,那就会导致 new 两次。

那怎么办呢?当我们通过第一个 if 检查后就赶紧加锁吧,只要锁住后,再判断 instance == nullptr 条件,如果依然成立,那么肯定表示这个单例对象还没有初始化,我们就可以放心创建类对象了。
现在两次检查的作用就比较清楚了。第一次检查是为了提高效率,如果对象已经创建了,就不用加锁了,直接返回;第二次检查是在加锁后进行,为了保证创建类对象的代码只有一个线程会执行。

再补充一下最简单的懒汉式代码,适用于单线程,如下。这么一回头看,是不是双重检查的因果就更明晰了。

static Singleton* getInstance() {
	if (instance == nullptr) {
        instance = new Singleton();
    }
    return instance;
}

Q.4 这种双重检查,有什么问题不

A.4

双重检查是为了在懒汉式实现单例模式时解决多个线程同时通过了第一个检查的问题。尽管双重检查可以在某种程度上提高性能和线程安全性,但它也存在以下问题:

  1. 可能导致指令重排序问题:在某些编译器和处理器架构中,为了提高性能,可能会对指令进行重排序。在没有正确的同步机制的情况下,可能会导致先给对象分配内存,再进行初始化操作,然后再将地址赋值给instance,这可能会导致其他线程获取到一个尚未正确初始化的对象。

  2. 可能引发内存可见性问题:由于多线程的执行是无序的,一个线程在初始化对象之后,其他线程可能无法立即看到最新的对象状态,从而导致获取到一个未正确初始化的对象,进而引发错误。

为了解决这些问题,可以使用C++11引入的 memory_order_acquire 和memory_order_release memory order 来对这两类问题进行指令重排保护和内存可见性保证,可以采用原子操作std::atomic_thread_fence来对指令进行序列化和内存栅栏等手段来实现线程安全的双重检查。

另外,C++11还引入了更简洁的线程安全单例模式实现方式,即基于静态局部变量的局部静态变量初始化,这种方式不需要显式的互斥锁或双重检查,由编译器保证线程安全性。示例如下:

class Singleton {
private:
    Singleton() {}

public:
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }
};

在这种方式下,静态局部变量instance在第一次调用getInstance()方法时被初始化,并且C++11标准保证了静态局部变量初始化的线程安全性。

总结起来,双重检查虽然能够一定程度上提高性能和线程安全性,但是需要注意在编写时要考虑到指令重排序和内存可见性问题,同时也要注意支持多线程的特定平台上的实现。在C++11及以后的版本中,可以使用基于静态局部变量的局部静态变量初始化来实现线程安全的单例模式

补充两个点。

第一,关于“先给对象分配内存,再进行初始化操作,然后再将地址赋值给instance”,这就是 instance = new Singleton()这行代码的理想执行顺序,并不会导致其他线程获取到一个尚未正确初始化的对象。考虑如下场景,指令重排序导致双重锁定失效,(箭头表示指令的执行顺序):
在这里插入图片描述
上图中线程 1 还没有将内存执行 instance 就切换到了线程 2,此时instance 依然为 nullptr,因此线程 2 也会进入创建流程,先让 instance 指向了红色的内存块,随后又切换回线程 1 的指令,又让 instance 指向了绿色的内存块。无论 instance 指针指向哪块内存,用户获得的都是一个正确初始化了的对象,而不是 AI 说的尚未正确初始化的对象,这只是导致了内存泄漏。

下面这样的指令重排序才会导致获得未初始化的对象
在这里插入图片描述

第二基于静态局部变量的局部静态变量初始化 这种方式,代码简单又安全,在 c++ 项目中还是比较常用的,至少我熟悉的是这种方式,除非你们的 c++ 版本还是11之前的,好吧。

Q.5 单例模式,是否需要把拷贝构造函数和拷贝赋值函数也设为私有呢

A.5

在单例模式中,将拷贝构造函数和拷贝赋值函数设为私有是一个常见的做法,旨在防止通过拷贝创建多个实例,确保只有一个实例存在。这样可以进一步加强单例模式的特性。

如果不将拷贝构造函数和拷贝赋值函数设为私有,那么可以通过拷贝创建多个实例,这可能破坏单例模式的意图。例如,如果有两个对象进行拷贝,那么就会有两个实例存在,违背了单例模式的原则。

为了避免这种情况,将拷贝构造函数和拷贝赋值函数设为私有可以有效地阻止对象的拷贝。这样一来,如果有人试图通过拷贝创建新的实例,编译器将会报错,提醒开发人员单例模式只允许存在一个实例。

以下是示例代码,演示如何将拷贝构造函数和拷贝赋值函数设为私有:

class Singleton {
private:
    static Singleton* instance;
    
    Singleton() {}  // 私有构造函数
    Singleton(const Singleton& other) {}  // 私有拷贝构造函数
    Singleton& operator=(const Singleton& other) { return *this; }  // 私有拷贝赋值函数

public:
    static Singleton* getInstance() {
        if(instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }
};

Singleton* Singleton::instance = nullptr;

通过将拷贝构造函数和拷贝赋值函数设为私有,确保了单例模式只存在一个实例,并且无法通过拷贝操作创建新的实例。这样可以防止意外创建多个对象,从而确保单例模式的正确性。

单例模式中,一般会将拷贝构造函数、赋值构造函数设置为私有,或者删除,防止出现多个实例。

Q.6 好的,总结一下上面几种单例模式写法的特点吧

A.6

下面是对上述几种单例模式写法的特点进行总结:

  1. 饿汉式:

    • 特点:在类加载时就创建好唯一实例,不存在多线程并发访问的安全问题。
    • 优点:实现简单,线程安全。
    • 缺点:可能造成资源浪费,因为实例在程序运行期间一直存在,无论是否被使用。
  2. 懒汉式(双重检查):

    • 特点:第一次获取实例时才进行实例化,避免了不必要的资源浪费。
    • 优点:实现较为灵活,只在需要时才创建实例;线程安全。
    • 缺点:需要解决指令重排序和内存可见性问题,实现稍复杂。
  3. 懒汉式(基于静态局部变量初始化):

    • 特点:使用静态局部变量的局部静态变量初始化,在需要时才进行实例化,并保证线程安全。
    • 优点:实现简洁,无需显式的锁或双重检查,由编译器保证线程安全性。
    • 缺点:在C++11及以后的版本才可使用。

对于饿汉式和懒汉式(双重检查),需要考虑多线程环境下的线程安全性,并采取相应的同步机制,如锁、互斥量、原子操作等,以保证单例模式的正确性。双重检查方式相对于饿汉式可以避免资源浪费,但需要在实现时注意解决指令重排序和内存可见性问题。

而懒汉式(基于静态局部变量初始化)是在C++11及以后的版本中引入的一种简洁的实现方式,由编译器保证线程安全性,无需显式的锁或双重检查。

选择哪种单例模式的实现方式,应根据具体的需求和环境来进行考虑。需要根据项目的特点和要求,综合考虑线程安全性、资源利用率以及实现复杂度等因素,选择适合的单例模式写法。

Q.7 单例模式,对象内存怎么释放呢

A.7

在单例模式中,对象的内存释放通常在程序结束时进行,因为单例模式的对象一般在整个程序执行期间都需要保持存在。因此,对象的内存释放由操作系统在程序退出时自动处理

对于懒汉式单例模式,由于对象的创建是在需要时进行的,因此对象的内存释放也应该在整个程序退出时进行。一般来说,操作系统会在程序结束时自动释放已分配的内存,包括单例对象的内存。

对于饿汉式单例模式和懒汉式(基于静态局部变量初始化)单例模式,在程序退出时,由于对象是静态变量,其内存会由操作系统自动释放。这是因为全局/静态变量的内存是在程序起始时分配的,操作系统会负责在程序结束时回收这些内存。

需要注意的是,如果在单例模式中使用了其他资源(如文件句柄、数据库连接等),则应该在程序结束前显式地释放这些资源。在单例类中提供一个公共的方法来释放资源是一个常见的做法,可供程序显式调用。

以下是示例代码,展示如何在单例模式中显式释放资源:

class Singleton {
private:
    // ...

public:
    // 获取单例实例的方法
    static Singleton& getInstance() {
        static Singleton instance;
        return instance;
    }

    // 释放资源的方法
    void releaseResources() {
        // 释放其他资源的代码
        // ...
    }
};

int main() {
    Singleton& singleton = Singleton::getInstance();

    // 使用单例对象...

    // 在程序结束前显式释放资源
    singleton.releaseResources();

    return 0;
}

在上述示例中,通过在单例类中添加一个releaseResources()方法,可以在程序结束前显式调用该方法来释放其他资源。

总结起来,在单例模式中,对象的内存释放由操作系统在程序结束时自动处理。但如果单例类中涉及到其他资源的占用,应该在程序退出前显式释放这些资源,以确保资源的正确释放。

单例模式,一般会将析构函数私有化,防止单例对象被意外释放。

Q.8 有什么办法,在程序结束时能主动回收单例对象占用的内存,而不是等操作系统来回收吗?

A.8

在一些特定的情况下,我们可能需要在程序结束时主动回收单例对象占用的内存,而不依赖于操作系统的自动回收。这可以通过调用单例类的析构函数来实现。

但是需要注意,对于单例模式而言,由于单例对象一般在整个程序运行期间都需要保持存在,主动释放单例对象占用的内存可能会导致对单例对象的再次访问时出现问题。因此,需要确保在主动释放内存后,不再对单例对象进行访问或使用

以下是一个示例代码,展示如何在程序结束时主动释放单例对象的内存:

class Singleton {
private:
    // 单例对象指针
    static Singleton* instance;

    // 私有构造函数和析构函数,确保单例对象的创建和销毁只能在内部进行
    Singleton() {}
    ~Singleton() {}

public:
    // 获取单例实例的方法
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
        }
        return instance;
    }

    // 删除拷贝构造函数和拷贝赋值运算符,确保单例对象不可复制
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // 主动释放单例对象的内存
    static void releaseInstance() {
        delete instance;
        instance = nullptr;
    }
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* singleton = Singleton::getInstance();

    // 使用单例对象...

    // 主动释放单例对象的内存
    Singleton::releaseInstance();

    return 0;
}

在上述示例中,我添加了一个静态指针instance作为单例对象的引用,通过调用getInstance()方法来获取单例对象。在releaseInstance()方法中,我们手动释放了该单例对象的内存,并将指针设为nullptr

需要明确,主动释放单例对象的内存是一种特殊情况,一般不建议在正常业务逻辑中使用。这样做可能会导致在之后再次使用单例对象时出现空悬指针或其他错误。在实际开发中,我们更倾向于让操作系统在程序结束时自动回收单例对象占用的内存。

Q.9 好的,我看网上有一种,在单例类中嵌套一个垃圾回收类的写法,给我说说呗

A.9

是的,你提到的在单例类中嵌套一个垃圾回收类的写法是一种常见的方式,用于在程序结束时自动释放单例对象的内存。这种方式利用了静态成员变量的析构函数在程序结束时被调用的特性

下面是一个示例代码,演示这种嵌套垃圾回收类的写法:

class Singleton {
private:
    // 垃圾回收类
    class GarbageCollector {
    public:
        ~GarbageCollector() {
            if (Singleton::instance) {
                delete Singleton::instance;
                Singleton::instance = nullptr;
            }
        }
    };

    // 单例对象指针
    static Singleton* instance;

public:
    // 获取单例实例的方法
    static Singleton* getInstance() {
        if (instance == nullptr) {
            instance = new Singleton();
            // 嵌套的垃圾回收类对象,在程序结束时自动释放单例对象的内存
            static GarbageCollector garbageCollector;
        }
        return instance;
    }

    // 删除拷贝构造函数和拷贝赋值运算符,确保单例对象不可复制
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;

    // ...其他成员函数...
};

// 初始化静态成员变量
Singleton* Singleton::instance = nullptr;

int main() {
    Singleton* singleton = Singleton::getInstance();

    // 使用单例对象...

    return 0;  // 在程序结束时,垃圾回收类的析构函数会被自动调用,释放单例对象的内存
}

在上述示例中,Singleton类中嵌套了一个名为GarbageCollector的垃圾回收类。在getInstance()方法中的单例对象创建逻辑中,我们使用了一个static修饰的GarbageCollector对象,这保证了它只会在程序的第一次调用getInstance()时创建,并且在程序结束时自动触发析构函数。

当程序结束时,嵌套的GarbageCollector对象会被销毁,它的析构函数会检查单例对象指针是否存在,然后释放单例对象的内存,并将其指针置为空指针

使用嵌套的垃圾回收类可以避免依赖于用户调用释放方法或注册退出处理函数,使得单例对象的内存释放更加自动化和方便

如果程序以非正常的方式终止,如崩溃或强制关闭,嵌套的垃圾回收类对象的析构函数可能不会被调用,导致单例对象的内存泄漏

Q.10 画一下单例模式的类图

A.10

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/757759.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【半监督医学图像分割 2022 IJCAI】UGPCL

文章目录 【半监督医学图像分割 2022 IJCAI】UGPCL摘要1. 介绍2. 相关工作2.1 半监督医学图像分割2.2 对比学习2.3 不确定度估计 3. 方法3.1 解码器间的一致性学习3.2 不确定性引导的对比学习3.3 等变对比损失 4. 实验4.1 实验设置4.2 定量实验4.3 消融实验 5. 结论 【半监督医…

引爆用户流量,打造热门小红书创业项目

引爆用户流量&#xff0c;打造热门小红书创业项目 在当今互联网时代&#xff0c;创业者们不断寻求新的商机和盈利模式。而小红书作为一个以分享购物心得、美妆、旅行等内容为主的社交平台&#xff0c;成为了众多创业者关注的焦点。如何通过小红书引爆用户流量&#xff0c;并打造…

【框架篇】使用注解存储对象

使用注解存储对象 之前我们存储Bean时&#xff0c;需要在spring-config 中添加一行 bean注册内容才行&#xff0c;如下图所示&#xff1a; 问题引入&#xff1a;如果想在Spring 中能够更简单的进行对象的存储和读取&#xff0c;该怎么办呢&#xff1f; 问题解答&#xff1a;实…

Python应用实例(一)外星人入侵(十)

外星人入侵&#xff08;十&#xff09; 1.记分1.1 显示得分1.2 创建记分牌1.3 在外星人被消灭时更新得分1.4 重置得分1.5 将消灭的每个外星人都计入得分1.6 提高分数1.7 舍入得分1.8 最高得分1.9 显示等级1.10 显示余下的飞船数 1.记分 下面来实现一个记分系统&#xff0c;以实…

动态规划01背包之1049 最后一块石头的重量 II(第11道)

题目&#xff1a; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 。那么粉碎的可能结果如下&#xff1a; …

4029: 网格行走

题目内容 在一个 n n n \times n nn 的网格上行走&#xff0c;从 ( 1 , 1 ) (1, 1) (1,1) 走到 ( n , n ) (n, n) (n,n)。每次只能向下走一步或向右走一步。 每个点 ( i , j ) (i, j) (i,j) 有权值 a i , j a_{i, j} ai,j​&#xff0c;给定一个数 x x x&#xff0c;求…

电机驱动系列(1)--例程下载演示

电机驱动系列&#xff08;1&#xff09; 使用设备连线实操感想 使用设备 硬件&#xff1a;野火骄阳板–STM32F407IGT6&#xff0c;野火无刷电机驱动板&#xff0c;PMSM电机软件&#xff1a;MCSDK&#xff0c;STM32CubeMX&#xff0c;Keil5软件安装注意事项&#xff1a;MCSDK-F…

SOF-SLAM论文翻译

SOF-SLAM:面向动态环境的语义可视化SLAM 摘要-同时定位与绘图(SLAM)在计算机视觉和机器人领域中占有重要地位。为了便于分析&#xff0c;传统的SLAM框架采用了强静态世界假设。如何应对动态环境是一个非常重要的问题&#xff0c;越来越受到人们的关注。现有的动态场景SLAM系统…

MySQL不适合创建索引的7种情况

1. 在where中使用不到的字段&#xff0c;不要设置索引 WHERE条件&#xff08;包括order by &#xff0c;group by&#xff09; 2. 数据量小的表最好不要使用索引 表记录太少&#xff0c;比如少于1000个&#xff0c;创建索引会先查索引&#xff0c;再回表&#xff0c;查询花费…

虚拟机安装及使用

无论下载什么软件&#xff0c;最好都要单独设置个文件夹 文章目录 VMware下载CentOS下载Xshell 7下载WinSCP下载linux命令 VMware下载 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; VMware Workstation Pro安装 一直傻瓜式安装 可以上网找许可证秘钥 …

asm: 实现打印“Hello, world!“

使用汇编打印“Hello, world!“ 实现打印"Hello, world!"的汇编代码代码详细剖析 实现打印"Hello, world!"的汇编代码 我们来直接贴代码 section .textglobal _start _start:mov edx,lenmov ecx,msgmov ebx,1mov eax,4 int 0x80mov …

pytest 通过装饰器获取测试case的断言失败结果

test11.py import logging from functools import wrapsdef log_exceptions(func):wraps(func)def wrapper(*args, **kwargs):# 创建日志记录器logger logging.getLogger(func.__name__)logger.setLevel(logging.ERROR)# 创建文件处理器file_handler logging.FileHandler(er…

MySQL(五)缓存策略

MySQL系列文章 MySQL&#xff08;一&#xff09;基本架构、SQL语句操作、试图 MySQL&#xff08;二&#xff09;索引原理以及优化 MySQL&#xff08;三&#xff09;SQL优化、Buffer pool、Change buffer MySQL&#xff08;四&#xff09;事务原理及分析 MySQL&#xff08;五&a…

利用pgloader工具将MySQL数据迁移至PostgreSQL数据库

一、简介 pgloader是一款开源软件,可以将各种来源的数据加载到PostgreSQL数据库中&#xff0c;支持动态读取数据&#xff0c;使用 COPY 流式传输协议将数据加载到 PostgreSQL 数据库中&#xff0c;并使用单独的线程读取和写入数据&#xff0c;由于能够直接从源数据库加载数据。…

1771_Windows下格式化Linux硬盘

全部学习汇总&#xff1a; GreyZhang/little_bits_of_linux: My notes on the trip of learning linux. (github.com) 我自己使用Linux系统多年&#xff0c;但是对于很多操作系统相关的知识我其实并不是很了解。我当初之所以使用Linux一是因为这个系统能够提供给我所有想要的工…

Unity游戏源码分享-Unity手游射击横版游戏

Unity游戏源码分享-Unity手游射击横版游戏 战斗场景 项目地址&#xff1a; https://download.csdn.net/download/Highning0007/88050256

Deployment:让应用永不宕机

“Deployment”&#xff0c;顾名思义&#xff0c;它是专门用来部署应用程序的&#xff0c;能够让应用永不宕机&#xff0c;多用来发布无状态的应用&#xff0c;是 Kubernetes 里最常用也是最有用的一个对象。 Deployment 的关键字段&#xff1a;先看 replicas 字段。它的含义比…

在Vitis IDE中使用第三方库 libtiff 保存 tiff 文件

目的和思路 一个Vitis IDE 裸机项目&#xff0c;需要将视频帧无损地保存下来 由于每帧的像素数据是 16bit 1通道的 bayer 格式&#xff0c;满足这一需求的图像格式似乎只有 tiff 格式 开源的tiff 库是 libtiff&#xff0c;而在 Vitis IDE 裸机项目中要使用的话就需要交叉编译…

AD22软件系统参数的一些基本设置

AD22软件系统参数设置 SystemData managementSchematicPCB Editor System Data management Schematic PCB Editor

集群基础5——keepalived对apache高可用

文章目录 一、基本了解二、配置文件参数释义2.1 默认配置文件2.2 定制配置文件2.2.1 vrrp_instance段配置参数2.2.2 vrrp_script段配置参数2.2.3 real_server段配置参数2.2.4 tcp_check段配置参数 三、keepalived对apache高可用3.1 环境说明3.2 安装服务3.3 配置主服务器3.4 配…