Python

  1. 异步编程

事件循环(Event Loop):事件循环是asyncio的核心,它负责调度和执行异步任务。当遇到await表达式时,事件循环会暂停当前协程,转而执行其他可运行的协程。

协程(Coroutine):协程是asyncio中的基本执行单元,使用async def定义。协程可以通过await关键字挂起自身,让出控制权给事件循环。

基本操作:

import asyncio
async fetch_data(url):
    await asyncio.sleep(2)
    return "Data"

# 主协程
async def main():
    tasks = [
        fetch_data("https://1.com"),
        fetch_data("https://2.com"),
        fetch_data("https://3.com")
    ]
    results = await asyncio.gather(*tasks)
    print(f"All results: {results}")

asyncio.run(main())
  1. GC机制、循环引用
x = []
y = [x]
x.append(y)
  1. 装饰器
  2. 单例

C++

  1. class与struct区别:使用 class 时,类中的成员默认都是 private 属性的;而使用 struct 时,结构体中的成员默认都是 public 属性的。
    1. 同理,class继承默认是 private 继承,而 struct 继承默认是 public 继承。
    2. 另外,class成员可以用模板,struct不行
  2. 内存管理
    1. 栈与堆:栈每个线程独立,没有碎片,指针向下移动,速度快;堆由程序员通过new/malloc手动管理,涉及查找内存块、分割/合并内存块、处理碎片等,速度慢。
#include <iostream>
#include <chrono>

void stackMemory() {
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; i++) {
        int arr[100]; // stack
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Stack Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() << "microseconds" <<std::endl;
}

void heapMemory() {
    auto start = std::chrono::high_resolution_clock::now();
    for (int i = 0; i < 1000000; i++) {
        int* arr = new int[100]; // heap
        delete[] arr; // release
    }
    auto end = std::chrono::high_resolution_clock::now();
    std::cout << "Heap Time: " << std::chrono::duration_cast<std::chrono::microseconds>(end-start).count() << "microseconds" <<std::endl;
}
2. brk与mmap
3. 内存对齐
1)空对象为1个字节。
struct A1 {};

(2) 每个元素,按照自身大小对齐;总大小按照最大元素倍数对齐
struct A2 {
    char a; // 1
    int b; // 4, 此时前面需要补3个字节
    unsigned short c; // 2
    long long d; // 8, 补6个
    char e; // 1
}; //最后,补充成8的倍数,sizeof(A2) == 1 + (3) + 4 + 2 + (6) + 8 + (1) + (7) = 32

(3) 普通函数不占字节,虚函数多8个字节(虚函数表指针)
struct A3 {
    void f() { // do something; }
};

struct A4 {
    virtual void f() { // do something; }
};

(4) #pragma pack(N) N必须是2的幂。如果下一个元素比N大,按照N对齐;否则按照下一个元素对齐
#pragma pack(2)
struct B1 {
    char a; // 1
    int b; // 4, 按照2对齐。如果是pragma pack(8),按照4对齐
} //最后的倍数与N无关,按照最大元素
#pragama pack() //取消pack

5__attribute__((packed)) 完全取消内存对齐;__attribute__((aligned)) 16字节对齐,aligned(N)指定字节对齐(需要N大于最大的元素)

6)如果一个结构里有某些结构体成员,则结构体成员要从其内部"最宽基本类型成员"的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,b应该从8的整数倍开始存储.)

7unionsize需要满足以下两个条件,第一:size大于等于最长元素的长度;第二,size是最大类型的整数倍。
union表示几个变量共用一个内存位置,并且同一时间只能储存其中一个成员变量的值。

typedef union{
    long i; //最大类型8
    char j[10]; //最长元素10
    int k;
}DATE; //所以是16
struct data{
    int m; // 4
    DATE n; //补充4个,按8存储
    double l; // 8
}test; // 4+(4)+16+8 == 32
  1. 智能指针
  2. 类型转换
  3. 手写string类型
  1. 手写vector
  2. memcpy,memmove,strcpy,snprinf,sprinf
    1. memcpy(不处理重叠策略)
void* memcpy(void* dest, const void* src, size_t n);
  1. C++多线程
    1. func1在线程1,func2在线程2,func2必须等待func1返回:
void func1() {
    // do something
    notify();
}
void func2() {
    // do something;
}
int main() {
    func1();
    wait();
    func2();
}
#include <iostream>
#include <mutex>
#include <condition_variable>
#include <thread>

std::mutex mtx;
std::condition_variable cv;
bool condition = false;

void func1() {
    std::cout << "Func1" << std::endl;
    {
        std::lock_guard<std::mutex> lock(mtx);
        condition = true;
    }
    cv.notify_one();
}
void func2() {
    // do something
}

int main() {
    std::thread t1(func1);
    {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [] { return condition; } );
    }
    std::cout << "Func1 Finished" << std::endl;
    func2();
    return 0;
}

这里引申出一个条件变量使用范式:

std::unique_lock<std::mutex> lock(mtx); //构造时对mtx加锁
cv.wait(lock, []{ return condition; }); //condition不为true,则释放锁并等待挂起
{
    std::lock_guard<std::mutex> lock(mtx); //尝试加锁
    condition = true;
} //作用域结束,析构则释放锁
cv.notify_one(); //唤醒一个等待的线程

信号量版本:

#include <iostream>
#include <semaphore>
#include <thread>

std::binary_semophore sem{0};

void func1() {
    std::cout << "do something" << std::endl;
    std::this_thread::sleep_for(std::chrono::miliseconds(500)); //this_thread 用来与当前线程交互,可以yield、get_id
    std::cout << "Release sem" << std::endl;
    sem.release();   
}

void func2() {
    // do something
}

int main() {
    std::thread t1(func1);
    std::cout << "Main thread is waiting" << std::endl;
    sem.acquire();
    std::cout << "Now we move on" << std::endl;
    func2();
    return 0;
}
  1. 如何用C实现多态?
  2. C++特性
    1. noexcept(C++11)

以下情形鼓励使用noexcept:

  • 移动构造函数(move constructor)
  • 移动分配函数(move assignment)

让标准库容器(如 <font style="color:rgb(0, 0, 0);background-color:rgb(239, 246, 255);">vector</font>)敢于使用移动而非保守地使用拷贝,极大提升性能

  • 析构函数(destructor)。这里提一句,在新版本的编译器中,析构函数是默认加上关键字noexcept的。

C++ 标准规定:如果异常传播到析构函数之外(即析构函数抛出异常并退出),程序会直接调用 **<font style="color:rgb(13, 18, 57);">std::terminate()</font>** 终止。在栈展开(stack unwinding)过程中,若多个异常同时存在(比如两个对象析构都抛异常),无法处理,只能终止。

2. 万能引用、完美转发
  1. 重载赋值运算
#include <iostream>
#include <string>

class Person {
private:
    std::string* name;  // 使用指针管理名字(仅作演示)

public:
    // 构造函数
    Person(const std::string& n) {
        name = new std::string(n);
        std::cout << "Construct: " << *name << "\n";
    }

    // 析构函数
    ~Person() {
        delete name;
        std::cout << "Destruct\n";
    }

    // 拷贝构造函数(深拷贝)
    Person(const Person& other) {
        name = new std::string(*(other.name));
        std::cout << "Copy construct: " << *name << "\n";
    }

    // ✅ 重载赋值运算符 =,返回类型引用,参数是const类型引用。基本按照4步走
    Person& operator=(const Person& other) {
        // 1. 检查自赋值
        if (this == &other) {
            return *this;
        }

        // 2. 释放当前资源
        delete name;

        // 3. 深拷贝
        name = new std::string(*(other.name));

        std::cout << "Assignment: " << *name << "\n";

        // 4. 返回引用
        return *this;
    }

    // 打印函数
    void print() const {
        std::cout << "Person{name=" << *name << "}\n";
    }
};

// 移动赋值
    ModernString& operator=(ModernString&& other) noexcept {
        if (this == &other) return *this;
        delete[] data;         // 释放当前资源
        data = other.data;     // 接管资源(而不是新开资源然后strcpy)
        other.data = nullptr;  // 防止 double delete
        return *this;
    }

copy and swap:

class String {
    char* str;
    String& operator=(String s) {
        s.swap(*this);
        return *this;
    }

    void swap(String& s) noexcept {
        std::swap(this->str, s.str);
    }
}

操作系统

tbd

数据库

tbd

网络

tbd