Vicuna
运行
安装依赖
1 | pip3 install torch transformers fschat |
下载
1 | llama 原始模型 |
更新参数
1 | python3 -m fastchat.model.apply_delta \ |
Serving
1 | nohup python3 -m fastchat.serve.controller & |
1 | pip3 install torch transformers fschat |
1 | llama 原始模型 |
1 | python3 -m fastchat.model.apply_delta \ |
1 | nohup python3 -m fastchat.serve.controller & |
详见这里。
1 | sudo apt-get purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras |
Ollama docker 容器找不到 GPU。
如果使用 docker compose,配置如下。
1 | services: |
解决。宿主机编辑 /etc/nvidia-container-runtime/config.toml
。
1 | no-cgroups = false # 修改, true -> false |
重启 docker。
1 | sudo systemctl restart docker |
1 | [sources.test] |
line_delimiter
1 | \b - backspace (U+0008) |
1 | [api] |
文档。
1 | pull image |
vector 在日志文件轮转之后,默认会计算日志文件的前n个字节的 check sum, 如果值一直,则不会监听新的文件。如果日志文件有固定的前缀,那么每次日志轮转,check sum 会保持一致,那么会无法切换至新的文件。
比如,vector 一开始监听 debug.log
文件,文件到达一定条件后做轮转操作,移动 debug.log
为 debug.log.1
,创建新的 debug.log
文件。如果 debug.log
和 debug.log.1
有相同的 check sum 值,那么 vector 不会监听新的文件。
修改 fingerprinter 的计算策略为 device_and_inode
。
1 | [sources.debug-log] |
epoll(event poll) 是 Linux 内核提供的一种高级 IO 多路复用机制,可以监听多个文件描述符上的事件,并将这些事件通知给应用程序,从而实现异步的 IO 操作。
epoll 监听的 fd(file descriptor)集合是常驻内核的,它有 3 个系统调用 (epoll_create, epoll_wait, epoll_ctl),通过 epoll_wait 可以多次监听同一个 fd 集合,只返回可读写那部分。
来自 ChatGPT
epoll 是 Linux 内核提供的一种高级 IO 多路复用机制,它可以同时监听多个文件描述符上的事件,并将这些事件通知给应用程序。与传统的 Select 和 Poll 机制相比,epoll 具有更高的性能和更好的可扩展性。
具体来说,epoll 通过以下几个关键部分来实现 IO 多路复用:
- epoll_create:创建一个 epoll 对象,并返回其对应的文件描述符。
- epoll_ctl:向 epoll 对象中添加或删除指定的文件描述符,以及设置相应的事件类型等参数。
- epoll_wait:等待指定文件描述符上的事件发生,并将这些事件收集起来返回给应用程序。
在使用 epoll 进行 IO 多路复用时,通常采取如下的处理流程:
- 创建 epoll 对象,并将需要监听的文件描述符添加到 epoll 的事件列表中。
- 使用 epoll_wait 等待事件的发生,当某个文件描述符上有事件发生时,就会触发 epoll_wait 返回。
- 根据事件类型进行相应的处理。如果是可读事件,则读取数据并进行处理;如果是可写事件,则进行写操作。
- 处理完毕后,将文件描述符从 epoll 的事件列表中删除。
需要注意的是,epoll 机制支持三种事件触发模式,包括边缘触发(Edge Triggered)、水平触发(Level Triggered)和一次性触发(One-Shot)。其中,边缘触发模式是最高效的一种模式,它只在文件描述符状态发生变化时才会通知应用程序;而水平触发和一次性触发模式需要更多的系统调用,因此相对较慢。
总的来说,epoll 机制具有高效、可扩展、灵活等优点,在高并发场景下被广泛使用。
epoll 如何通知应用程序
在 epoll 机制中,当 I/O 事件发生时,应用程序通过调用 epoll_wait 函数等待事件的发生。该函数会阻塞当前线程,直到有事件发生或者超时,然后将所有已经就绪的文件描述符加入到一个由 epoll_event 结构体组成的数组中,最后返回数组中的事件数量。
每个 epoll_event 结构体包含了一个就绪的文件描述符和该文件描述符上发生的事件类型。应用程序随后可以遍历这个数组,并根据文件描述符和其对应的事件类型进行相应的处理(如读取数据、写入数据等)。
需要注意的是,在边缘触发模式下,如果有多个事件同时发生,epoll_wait 只会返回一次通知。因此,应用程序在处理完某个文件描述符上的事件后,需要重新调用 epoll_wait 函数获取下一轮事件通知。
总之,epoll 机制的通知方式是通过将就绪的文件描述符和相应的事件类型打包成一个结构体,并返回给应用程序,从而实现了高效、可扩展、高并发的 IO 处理。
select 只有一个系统调用,每次要监听都要将其从用户态传到内核,有事件时返回整个集合。
来自 ChatGPT
select 是一种基于 IO 多路复用的系统调用,它可以同时监听多个文件描述符上的事件,并在其中有事件发生时通知应用程序进行处理。select 机制主要由以下三个部分组成:
- fd_set 数据结构:用于存储需要监听的文件描述符集合。
- select 函数:用于将需要监听的文件描述符集合传递给内核,以及等待事件的发生并返回事件列表。
- 相应的文件操作函数:例如 read、write 等,用于对文件描述符执行相应的 IO 操作。
在使用 select 进行 IO 多路复用时,通常采取如下的处理流程:
- 创建 fd_set 数据结构,并将需要监听的文件描述符添加到该数据结构中。
- 调用 select 函数等待事件的发生。当某个文件描述符上有事件发生时,就会触发 select 返回。
- 使用相应的文件操作函数对事件进行处理。如果是可读事件,则读取数据并进行相应的处理;如果是可写事件,则进行写操作。
- 循环执行上述过程,直到关闭连接或出现异常。
需要注意的是,在 select 模式下,文件描述符数量受到限制,通常不能超过系统默认值(例如 1024)。此外,在高并发情况下,select 的效率较低,因为每次都需要对所有监控的文件描述符进行扫描,无法有效利用 CPU 和内存等资源。因此,在实现高并发服务器时,通常采用更为高效的机制,如 epoll 和 kqueue 等。
示例
1 | Protocol protocol = { ParseMessage, |
客户端调用顺序
1 | bthread_t bid; |
1 | include "bthread/bthread.h" |
NOTE: 执行一次,且时间为时间戳(通常是未来时间),非间隔执行。
1 |
|
自定义 Period Timer
1 | // brpc_period_timer.h |
概念 | 标签 | 说明 |
---|---|---|
平衡树 | 二叉树 | 可以保证在插入、删除等操作后维持树的平衡性,以保证其查找效率 |
B树 | 多路搜索树、自平衡搜索树 | 每个节点可以拥有多于两个的子节点,常用于磁盘文件系统和数据库索引等场景 |
B+树 | 多路搜索树、自平衡搜索树 | 优化了B树的节点结构和叶子节点指针,提供了更好的范围查询性能。它在数据库索引和文件系统中广泛应用,能够高效地支持各种查询操作 |
B-树 | 多路搜索树、自平衡搜索树 | 具有多个关键字的非叶子节点和链表连接的叶子节点。它在节点结构、关键字排序和范围查询性能等方面与B树和B+树有所不同。B-树适用于大规模数据集的存储和检索,能够提供高效的访问性能 |
红黑树 | 平衡二叉查找树 | gpt-3.5-turbo-0613由于其插入、删除和查找的时间复杂度均为O(log(n)),因此被广泛应用于STL中的set和map容器 |
Trie树(字典树) | 多叉树结构 | 用于检索字符串数据集中的键值,常用于搜索引擎词频统计等场景 |
堆 | 完全二叉树 | 连续内存存储,可用于实现优先队列等数据结构。堆分为大根堆和小根堆两种类型 |
Huffman树 | 二叉树 | 一种带权路径长度最短的二叉树,常用于数据压缩和编码等场景 |
数据结构 | 底层存储 | 复杂度 |
---|---|---|
map | 红黑树 | O(logn) |
unordered_map | 散列表 | O(1) |
list | 双向链表 | O(n) |
priority_queue | 堆(数组实现) | O(logn) |
sort()
函数通常使用一种名为 “introsort” 的混合排序算法来实现。这是一种综合了快速排序、堆排序和插入排序的排序算法。sort()
函数首先会尝试使用快速排序算法进行排序,通过选择一个枢轴元素来将序列分割成两个部分,并递归地对子序列进行排序。当递归深度达到一定阈值时,为了避免最坏情况下的时间复杂度,算法会转而采用堆排序算法。如果序列较小,则会使用插入排序算法进行排序。底层实现:quick_sort()
函数是基于快速排序算法的一种实现。
工作原理:快速排序算法通过选取一个枢轴元素将序列分割为两个子序列,较小的元素放在枢轴的左侧,较大的元素放在右侧。然后对这两个子序列递归地应用相同的操作,直到子序列的大小为 1 或 0,此时递归结束。
复杂度:平均时间复杂度为 O(n log n),其中 n 是待排序序列的大小。最坏情况下的时间复杂度为 O(n^2)。空间复杂度为 O(log n)。
STL(Standard Template Library,标准模板库)是C++编程语言的一个标准库,主要包含了许多常用的数据结构和算法,并为其提供了一系列的通用接口,方便开发者进行快速开发、高效地复用代码。
STL包括容器、迭代器、算法以及仿函数等组件,它们的设计思想是基于泛型编程和模板元编程。STL允许用户通过重载运算符或定义函数对象对其现有的模板进行扩展,支持自定义类型和算法,从而大大增强了程序的可扩展性和可维护性。
STL标准库中包含了很多容器(如vector、list、map、set等)、算法(如sort、search、find等)和迭代器(如输入输出流迭代器、反向迭代器等),这些组件可以帮助程序员实现许多常见的数据结构和算法,例如线性表、树、图、排序、查找等,从而提高了程序的开发效率和代码质量。
总之,STL是一种非常强大和实用的C++库,广泛应用于软件开发、算法竞赛等领域,是C++程序员必须掌握的一个重要工具。
STL(Standard Template Library,标准模板库)中包含了多种容器,主要分为以下三类:
顺序容器是指元素按照一定的顺序存储和访问的容器。常见的顺序容器有vector、list、deque、array等。其中,vector和deque都是基于数组实现的可变长度容器,而list则是基于双向链表实现的容器。
关联容器是指元素按照一定规则排序后存储和访问的容器。常见的关联容器有set、multiset、map、multimap等。其中,set和map是基于平衡二叉树实现的,而multiset和multimap允许重复元素。
无序容器是指元素不按照任何特定顺序存储和访问的容器。常见的无序容器有unordered_set、unordered_multiset、unordered_map、unordered_multimap等。这些容器通常使用哈希表来实现,具有O(1)的插入、查找和删除操作。
这些容器之间的区别主要包括以下几个方面:
在选择容器时,需要根据具体的应用场景和需要进行权衡和选择。例如,如果需要对元素进行频繁的插入和删除操作,可以选择使用list或deque;如果需要高效地进行查找操作,则可以选择使用set、map等关联容器;如果需要快速进行元素的插入、查找和删除操作,则可以选择使用unordered_set、unordered_map等无序容器。
STL(Standard Template Library,标准模板库)中包含了大量的算法,这些算法主要分为以下几类:
这些算法的时间复杂度各不相同,具体如下:
STL(Standard Template Library)中的迭代器是一种用于遍历容器中各个元素的对象。根据其所支持的操作和能力,可以将迭代器分为以下五类:
std::istream_iterator
。std::ostream_iterator
。std::forward_list::iterator
。std::list::iterator
。std::vector::iterator
。这些迭代器之间的区别在于它们所支持的操作和能力不同。输入迭代器和输出迭代器都只能向前遍历容器中的元素,且不能进行修改、重复访问等操作。前向迭代器可以在容器中向前遍历每个元素,并且能够多次读取或写入同一元素。双向迭代器可以支持反向遍历容器并进行修改操作,而随机访问迭代器则可以支持高级的指针算术、下标操作等。
使用迭代器可以方便地对STL中的容器进行遍历和操作,从而简化代码的编写和维护。在实际应用中,我们可以根据需要选择合适的迭代器类型来完成相应的任务。
STL中的迭代器失效是指,当容器发生插入、删除或移动元素等操作时,之前获取的某些迭代器可能会失效,导致使用这些迭代器访问容器时出现未定义行为。
为了避免迭代器失效,可以采取以下措施:
STL中的容器和算法都是采用模板类和泛型编程的方式实现的。
容器是通过模板类来实现的,每个容器都有自己的特定类型、迭代器和操作方法。例如,vector容器是使用动态数组来实现的,list容器是使用双向链表来实现的,map容器是使用红黑树来实现的等等。
算法是通过函数模板来实现的,它们可以接受不同类型的容器和迭代器作为参数,并提供了一系列通用的操作方法。例如,sort()函数可以对任何支持随机访问迭代器的容器进行排序,find()函数可以在任何支持正向迭代器的容器中查找指定元素等等。
这种基于模板类和泛型编程的设计模式,使得STL中的容器和算法具有高度的灵活性和可重用性,可以适应各种数据结构和算法的实现需求。同时还能够提高代码的可读性和可维护性,减少了重复代码的写作量,提高了开发效率。
在 这里 选择规格,并下载。以 amd64 的 ubuntu 为例,下面是在线安装命令。
1 | wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu2204/x86_64/cuda-keyring_1.0-1_all.deb |
1 | 安装 |
不启用认证配置
1 | logoutput: /var/log/danted.log |
1 | 安装 |
1 | 安装 |