Linux-C/C++--深入探究文件 I/O (下)(文件共享、原子操作与竞争冒险、系统调用、截断文件)
经过上一章内容的学习,了解了 Linux 下空洞文件的概念;open 函数的 O_APPEND 和 O_TRUNC 标志;多次打开同一文件;复制文件描述符;等内容
本章将会接着探究文件IO,讨论如下主题内容。
文件共享介绍;
原子操作与竞争冒险;
系统调用 fcntl() 和 ioctl() 介绍;
截断文件;
一、文件共享
什么是文件共享?所谓文件共享指的是同一个文件(譬如磁盘上的同一个文件,对应同一个 inode)被多个独立的读写体同时进行 IO 操作。多个独立的读写体大家可以将其简单地理解为对应于同一个文件的多个不同的文件描述符,譬如多次打开同一个文件所得到的多个不同的 fd,或使用 dup()(或 dup2)函数复制得到的多个不同的 fd 等。
同时进行 IO 操作指的是一个读写体操作文件尚未调用 close 关闭的情况下,另一个读写体去操作文件,前面给大家编写的示例代码中就已经涉及到了文件共享的内容了,譬如 3.6 小节中编写的示例代码中,同一个文件对应两个不同的文件描述符 fd1 和 fd2,当使用 fd1 对文件进行写操作之后,并没有关闭 fd1,而此时使用 fd2 对文件再进行写操作,这其实就是一种文件共享。
文件共享的意义有很多,多用于多进程或多线程编程环境中,譬如我们可以通过文件共享的方式来实现多个线程同时操作同一个大文件,以减少文件读写时间、提升效率。
文件共享的核心是:如何制造出多个不同的文件描述符来指向同一个文件。其实方法在上面的内容中都已经给大家介绍过了,譬如多次调用 open 函数重复打开同一个文件得到多个不同的文件描述符、使用 dup()或 dup2()函数对文件描述符进行复制以得到多个不同的文件描述符。
常见的三种文件共享的实现方式
(1)同一个进程中多次调用 open 函数打开同一个文件,各数据结构之间的关系如下图所示:
这种情况非常简单,多次调用 open 函数打开同一个文件会得到多个不同的文件描述符,并且多个文件描述符对应多个不同的文件表,所有的文件表都索引到了同一个 inode 节点,也就是磁盘上的同一个文件。
(2)不同进程中分别使用 open 函数打开同一个文件,其数据结构关系图如下所示:
进程 1 和进程 2 分别是运行在 Linux 系统上两个独立的进程(理解为两个独立的程序),在他们各自的程序中分别调用 open 函数打开同一个文件,进程 1 对应的文件描述符为 fd1,进程 2 对应的文件描述符为fd2,fd1 指向了进程 1 的文件表 1,fd2 指向了进程 2 的文件表 2;各自的文件表都索引到了同一个 inode 节点,从而实现共享文件。
(3)同一个进程中通过 dup(dup2)函数对文件描述符进行复制,其数据结构关系如下图所示:
对于文件共享,存在着竞争冒险,这个是需要大家关注的,下一小节将会向大家介绍。除此之外,我们还需要关心的是文件共享时,不同的读写体之间是分别写还是接续写,这些细节问题大家都要搞清楚。
二、原子操作与竞争冒险
Linux 是一个多任务、多进程操作系统,系统中往往运行着多个不同的进程、任务,多个不同的进程就有可能对同一个文件进行 IO 操作,此时该文件便是它们的共享资源,它们共同操作着同一份文件;操作系统级编程不同于大家以前接触的裸机编程,裸机程序中不存在进程、多任务这种概念,而在 Linux 系统中,我们必须要留意到多进程环境下可能会导致的竞争冒险。
1、竞争冒险简介
本小节给大家竞争冒险这个概念,如果学习过 Linux 驱动开发的读者对这些概念应该并不陌生,也就意味着竞争冒险不但存在于 Linux 应用层、也存在于 Linux 内核驱动层。
假设有两个独立的进程 A 和进程 B 都对同一个文件进行追加写操作(也就是在文件末尾写入数据),每一个进程都调用了 open 函数打开了该文件,但未使用 O_APPEND 标志,此时,各数据结构之间的关系如图 3.8.2 所示。每个进程都有它自己的进程控制块 PCB,有自己的文件表(意味着有自己独立的读写位置偏移量),但是共享同一个 inode 节点(也就是对应同一个文件)。假定此时进程 A 处于运行状态,B 未处于等待运行状态,进程 A 调用了 lseek 函数,它将进程 A 的该文件当前位置偏移量设置为 1500 字节处(假设这里是文件末尾),刚好此时进程 A 的时间片耗尽,然后内核切换到了进程 B,进程 B 执行 lseek 函数,也将其对该文件的当前位置偏移量设置为 1500 个字节处(文件末尾)。然后进程 B 调用 write 函数,写入了 100 个字节数据,那么此时在进程 B 中,该文件的当前位置偏移量已经移动到了 1600 字节处。B 进程时间片耗尽,内核又切换到了进程 A,使进程 A 恢复运行,当进程 A 调用 write 函数时,是从进程 A 的该文件当前位置偏移量(1500 字节处)开始写入,此时文件 1500 字节处已经不再是文件末尾了,如果还从 1500字节处写入就会覆盖进程 B 刚才写入到该文件中的数据。其上述假设工作流程图如下图所示:
2、原子操作
在上一章给大家介绍 open 函数的时候就提到过“原子操作”这个概念了,同样在 Linux 驱动编程中,也有这个概念,相信学习过 Linux 驱动编程开发的读者应该有印象。从上一小节给大家提到的示例中可知,上述的问题出在逻辑操作“先定位到文件末尾,然后再写”,它
使用了两个分开的函数调用,首先使用 lseek 函数将文件当前位置偏移量移动到文件末尾、然后在使用 write函数将数据写入到文件。既然知道了问题所在,那么解决办法就是将这两个操作步骤合并成一个原子操作,所谓原子操作,是有多步操作组成的一个操作,原子操作要么一步也不执行,一旦执行,必须要执行完所有步骤,不可能只执行所有步骤中的一个子集。
(1)O_APPEND 实现原子操作
在上一小节给大家提到的示例中,进程 A 和进程 B 都对同一个文件进行追加写操作,导致进程 A 写入的数据覆盖了进程 B 写入的数据,解决办法就是将“先定位到文件末尾,然后写”这两个步骤组成一个原子操作即可,那如何使其变成一个原子操作呢?答案就是 O_APPEND 标志。前面已经给大家多次提到过了 O_APPEND 标志,但是并没有给大家介绍 O_APPEND 的一个非常重要
的作用,那就是实现原子操作。当 open 函数的 flags 参数中包含了 O_APPEND 标志,每次执行 write 写入操作时都会将文件当前写位置偏移量移动到文件末尾,然后再写入数据,这里“移动当前写位置偏移量到文件末尾、写入数据”这两个操作步骤就组成了一个原子操作,加入 O_APPEND 标志后,不管怎么写入数据都会是从文件末尾写,这样就不会导致出现“进程 A 写入的数据覆盖了进程 B 写入的数据”这种情况了。
(2)pread()和 pwrite()
pread()和 pwrite()都是系统调用,与 read()、write()函数的作用一样,用于读取和写入数据。区别在于,pread()和 pwrite()可用于实现原子操作,调用 pread 函数或 pwrite 函数可传入一个位置偏移量 offset 参数,用于指定文件当前读或写的位置偏移量,所以调用 pread 相当于调用 lseek 后再调用 read;同理,调用 pwrite相当于调用 lseek 后再调用 write。所以可知,使用 pread 或 pwrite 函数不需要使用 lseek 来调整当前位置偏移量,并会将“移动当前位置偏移量、读或写”这两步操作组成一个原子操作。 pread、pwrite 函数原型如下所示(可通过"man 2 pread"或"man 2 pwrite"命令来查看):
#include <unistd.h>
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
首先调用这两个函数需要包含头文件<unistd.h>。
函数参数和返回值含义如下:
fd、buf、count 参数与 read 或 write 函数意义相同。
offset:表示当前需要进行读或写的位置偏移量。
返回值:返回值与 read、write 函数返回值意义一样。
虽然 pread(或 pwrite)函数相当于 lseek 与 pread(或 pwrite)函数的集合,但还是有下列区别:
调用 pread 函数时,无法中断其定位和读操作(也就是原子操作);
不更新文件表中的当前位置偏移量。
关于第二点我们可以编写一个简单地代码进行测试,测试代码如下所示:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{unsigned char buffer[100];int fd;int ret;/* 打开文件 test_file */fd = open("./test_file", O_RDWR);if (-1 == fd) {perror("open error");exit(-1);}/* 使用 pread 函数读取数据(从偏移文件头 1024 字节处开始读取) */ret = pread(fd, buffer, sizeof(buffer), 1024);if (-1 == ret) {perror("pread error");goto err;}/* 获取当前位置偏移量 */ret = lseek(fd, 0, SEEK_CUR);if (-1 == ret) {perror("lseek error");goto err;}printf("Current Offset: %d\n", ret);ret = 0;
err:/* 关闭文件 */close(fd);exit(ret);
}
在当前目录下存在一个文件 test_file,上述代码中会打开 test_file 文件,然后直接使用 pread 函数读取100 个字节数据,从偏移文件头部 1024 字节处,读取完成之后再使用 lseek 函数获取到文件当前位置偏移量,并将其打印出来。假如 pread 函数会改变文件表中记录的当前位置偏移量,则打印出来的数据应该是1024 + 100 = 1124;如果不会改变文件表中记录的当前位置偏移量,则打印出来的数据应该是 0,接下来编译代码测试:
从上图中可知,打印出来的数据为 0,正如前面所介绍那样,pread 函数确实不会改变文件表中记录的当前位置偏移量;同理,pwrite 函数也是如此,大家可以把 pread 换成 pwrite 函数再次进行测试,不出意外,打印出来的数据依然是 0。
如果把 pread 函数换成 read(或 write)函数,那么打印出来的数据就是 100 了,因为读取了 100 个字节数据,相应的当前位置偏移量会向后移动 100 个字节。
三、fcntl 和 ioctl
1、fcntl 函数
cntl()函数可以对一个已经打开的文件描述符执行一系列控制操作,譬如复制一个文件描述符(与 dup、dup2 作用相同)、获取/设置文件描述符标志、获取/设置文件状态标志等,类似于一个多功能文件描述符管理工具箱。fcntl()函数原型如下所示(可通过"man 2 fcntl"命令查看)
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ )
函数参数和返回值含义如下:
fd:文件描述符。
cmd:操作命令。此参数表示我们将要对 fd 进行什么操作,cmd 参数支持很多操作命令,大家可以打
开 man 手册查看到这些操作命令的详细介绍,这些命令都是以 F_XXX 开头的,譬如 F_DUPFD、F_GETFD、F_SETFD 等,不同的 cmd 具有不同的作用,cmd 操作命令大致可以分为以下 5 种功能:
复制文件描述符(cmd=F_DUPFD 或 cmd=F_DUPFD_CLOEXEC);
获取/设置文件描述符标志(cmd=F_GETFD 或 cmd=F_SETFD);
获取/设置文件状态标志(cmd=F_GETFL 或 cmd=F_SETFL);
获取/设置异步 IO 所有权(cmd=F_GETOWN 或 cmd=F_SETOWN);
获取/设置记录锁(cmd=F_GETLK 或 cmd=F_SETLK);
这里列举出来,并不需要全部学会每一个 cmd 的作用,因为有些内容并没有给大家提及到,譬如什么异步 IO、锁之类的概念,在后面的学习过程中,当学习到相关知识内容的时候再给大家介绍。
…:fcntl 函数是一个可变参函数,第三个参数需要根据不同的 cmd 来传入对应的实参,配合 cmd 来使
用。
返回值:执行失败情况下,返回-1,并且会设置 errno;执行成功的情况下,其返回值与 cmd(操作命令)有关,譬如 cmd=F_DUPFD(复制文件描述符)将返回一个新的文件描述符、cmd=F_GETFD(获取文件描述符标志)将返回文件描述符标志、cmd=F_GETFL(获取文件状态标志)将返回文件状态标志等。
fcntl 使用示例
(1)复制文件描述符
前面给大家介绍了 dup 和 dup2,用于复制文件描述符,除此之外,我们还可以通过 fcntl 函数复制文件描 述 符 , 可 用 的 cmd 包 括 F_DUPFD 和 F_DUPFD_CLOEXEC , 这 里 就 只 介 绍 F_DUPFD ,F_DUPFD_CLOEXEC 暂时先不讲。
当 cmd=F_DUPFD 时,它的作用会根据 fd 复制出一个新的文件描述符,此时需要传入第三个参数,第三个参数用于指出新复制出的文件描述符是一个大于或等于该参数的可用文件描述符(没有使用的文件描述符);如果第三个参数等于一个已经存在的文件描述符,则取一个大于该参数的可用文件描述符。
测试代码如下所示:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int fd1, fd2;int ret;/* 打开文件 test_file */fd1 = open("./test_file", O_RDONLY);if (-1 == fd1) {perror("open error");exit(-1);}/* 使用 fcntl 函数复制一个文件描述符 */fd2 = fcntl(fd1, F_DUPFD, 0);if (-1 == fd2) {perror("fcntl error");ret = -1;goto err;}printf("fd1: %d\nfd2: %d\n", fd1, fd2);ret = 0;close(fd2);
err:/* 关闭文件 */close(fd1);exit(ret);
}
在当前目录下存在 test_file 文件,上述代码会打开此文件,得到文件描述符 fd1,之后再使用 fcntl 函数复制 fd1 得到新的文件描述符 fd2,并将 fd1 和 fd2 打印出来,接下来编译运行:

可知复制得到的文件描述符是 7,因为在执行 fcntl 函数时,传入的第三个参数是 0,也就时指定复制得到的新文件描述符必须要大于或等于 0,但是因为 0~6 都已经被占用了,所以分配得到的 fd 就是 7;如果传入的第三个参数是 100,那么 fd2 就会等于 100,大家可以自己动手测试。
(2)获取/设置文件状态标志
cmd=F_GETFL 可用于获取文件状态标志,cmd=F_SETFL 可用于设置文件状态标志。cmd=F_GETFL 时不需要传入第三个参数,返回值成功表示获取到的文件状态标志;cmd=F_SETFL 时,需要传入第三个参数,此参数表示需要设置的文件状态标志。
这些标志指的就是我们在调用 open 函数时传入的 flags 标志,可以指定一个或多个(通过位或 | 运算符组合),但是文件权限标志(O_RDONLY、O_WRONLY、O_RDWR)以及文件创建标志(O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC)不能被设置、会被忽略;在 Linux 系统中,只有 O_APPEND、O_ASYNC、O_DIRECT、O_NOATIME 以及 O_NONBLOCK 这些标志可以被修改,这里面有些标志并没有给大家介绍过,后面我们在用到的时候再给大家介绍。所以对于一个已经打开的文件描述符,可以通过这种方式添加或移除标志。
测试代码如下:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{int fd;int ret;int flag;/* 打开文件 test_file */fd = open("./test_file", O_RDWR);if (-1 == fd) {perror("open error");exit(-1);}/* 获取文件状态标志 */flag = fcntl(fd, F_GETFL);if (-1 == flag) {perror("fcntl F_GETFL error");ret = -1;goto err;}printf("flags: 0x%x\n", flag);/* 设置文件状态标志,添加 O_APPEND 标志 */ret = fcntl(fd, F_SETFL, flag | O_APPEND);if (-1 == ret) {perror("fcntl F_SETFL error");goto err;}ret = 0;
err:/* 关闭文件 */close(fd);exit(ret);
}
以上给大家介绍了 fcntl 函数的两种用法,除了这两种用法之外,还有其它多种不同的用法,这里暂时先不介绍了,后面学习到相应知识点的时候再给大家讲解。
2、ioctl 函数
ioctl()可以认为是一个文件 IO 操作的杂物箱,可以处理的事情非常杂、不统一,一般用于操作特殊文件或硬件外设,此函数将会在进阶篇中使用到,譬如可以通过 ioctl 获取 LCD 相关信息等,本小节只是给大家引出这个系统调用,暂时不会用到。此函数原型如下所示(可通过"man 2 ioctl"命令查看):
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
函数参数和返回值含义如下:
fd:文件描述符。
request:此参数与具体要操作的对象有关,没有统一值,表示向文件描述符请求相应的操作;后面用到的时候再给大家介绍。
...:此函数是一个可变参函数,第三个参数需要根据 request 参数来决定,配合 request 来使用。
返回值:成功返回 0,失败返回-1。
四、截断文件
使用系统调用 truncate()或 ftruncate()可将普通文件截断为指定字节长度,其函数原型如下所示:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char *path, off_t length);
int ftruncate(int fd, off_t length);
这两个函数的区别在于:ftruncate()使用文件描述符 fd 来指定目标文件,而 truncate()则直接使用文件路径 path 来指定目标文件,其功能一样。
这两个函数都可以对文件进行截断操作,将文件截断为参数 length 指定的字节长度,什么是截断?如果文件目前的大小大于参数 length 所指定的大小,则多余的数据将被丢失,类似于多余的部分被“砍”掉了;如果文件目前的大小小于参数 length 所指定的大小,则将其进行扩展,对扩展部分进行读取将得到空字节"\0"。
使用 ftruncate()函数进行文件截断操作之前,必须调用 open()函数打开该文件得到文件描述符,并且必须要具有可写权限,也就是调用 open()打开文件时需要指定 O_WRONLY 或 O_RDWR。
调用这两个函数并不会导致文件读写位置偏移量发生改变,所以截断之后一般需要重新设置文件当前的读写位置偏移量,以免由于之前所指向的位置已经不存在而发生错误(譬如文件长度变短了,文件当前所指向的读写位置已不存在)。
调用成功返回 0,失败将返回-1,并设置 errno 以指示错误原因。
使用示例
示例代码 3.11.1 演示了文件的截断操作,分别使用 ftruncate()和 truncate()将当前目录下的文件 file1 截断为长度 0、将文件 file2 截断为长度 1024 个字节。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void)
{int fd;/* 打开 file1 文件 */if (0 > (fd = open("./file1", O_RDWR))) {perror("open error");exit(-1);}/* 使用 ftruncate 将 file1 文件截断为长度 0 字节 */if (0 > ftruncate(fd, 0)) {perror("ftruncate error");exit(-1);}/* 使用 truncate 将 file2 文件截断为长度 1024 字节 */if (0 > truncate("./file2", 1024)) {perror("truncate error");exit(-1);}/* 关闭 file1 退出程序 */close(fd);exit(0);
}
上述代码中,首先使用 open()函数打开文件 file1,得到文件描述符 fd,接着使用 ftruncate()系统调用将 文件截断为 0 长度,传入 file1 文件对应的文件描述符;接着调用 truncate()系统调用将文件 file2 截断为 1024字节长度,传入 file2 文件的相对路径。
接下来进行测试,在当前目录下准备两个文件 file1 和 file2,如下所示:
可以看到 file1 和 file2 文件此时均为 592 字节大小,接下来运行测试代码:
程序运行之后,file1 文件大小变成了 0,而 file2 文件大小变成了 1024 字节,与测试代码想要实现的功能是一致的。
相关文章:
Linux-C/C++--深入探究文件 I/O (下)(文件共享、原子操作与竞争冒险、系统调用、截断文件)
经过上一章内容的学习,了解了 Linux 下空洞文件的概念;open 函数的 O_APPEND 和 O_TRUNC 标志;多次打开同一文件;复制文件描述符;等内容 本章将会接着探究文件IO,讨论如下主题内容。 文件共享介绍&…...
Linux Bash 中使用重定向运算符的 5 种方法
注:机翻,未校。 Five ways to use redirect operators in Bash Posted: January 22, 2021 | by Damon Garn Redirect operators are a basic but essential part of working at the Bash command line. See how to safely redirect input and output t…...
opengrok_windows_环境搭建
目录 软件列表 软件安装 工程索引 编辑 工程部署 问题列表 软件列表 软件名下载地址用途JDKhttps://download.java.net/openjdk/jdk16/ri/openjdk-1636_windows-x64_bin.zipindex 使用java工具tomcathttps://dlcdn.apache.org/tomcat/tomcat-9/v9.0.98/bin/apache-tom…...
【无法下载github文件】虚拟机下ubuntu无法拉取github文件
修改hosts来进行解决。 步骤一:打开hosts文件 sudo vim /etc/hosts步骤二:查询 github.com的ip地址 https://sites.ipaddress.com/github.com/#ipinfo将github.com的ip地址添加到hosts文件末尾,如下所示。 140.82.114.3 github.com步骤三…...
python——句柄
一、概念 句柄指的是操作系统为了标识和访问对象而提供的一个标识符,在操作系统中,每个对象都有一个唯一的句柄,通过句柄可以访问对象的属性和方法。例如文件、进程、窗口等都有句柄。在编程中,可以通过句柄来操作这些对象&#x…...
.Net Core微服务入门系列(一)——项目搭建
系列文章目录 1、.Net Core微服务入门系列(一)——项目搭建 2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上) 3、.Net Core微服务入门全纪录(三)——Consul-服务注…...
Net Core微服务入门全纪录(三)——Consul-服务注册与发现(下)
系列文章目录 1、.Net Core微服务入门系列(一)——项目搭建 2、.Net Core微服务入门全纪录(二)——Consul-服务注册与发现(上) 3、.Net Core微服务入门全纪录(三)——Consul-服务注…...
[苍穹外卖] 1-项目介绍及环境搭建
项目介绍 定位:专门为餐饮企业(餐厅、饭店)定制的一款软件产品 功能架构: 管理端 - 外卖商家使用 用户端 - 点餐用户使用 技术栈: 开发环境的搭建 整体结构: 前端环境 前端工程基于 nginx 运行 - Ngi…...
【PCIe 总线及设备入门学习专栏 2 -- PCIe 的 LTSSM 和 Enumeration】
文章目录 OverviewLTSSM StatesDetect StatesDETECT_QUIETDETECT_ACTDETECT_WAITPolling StatesPOLL_ACTIVEPOLL_CONFIGPOLL_COMPLIANCEConfiguration StatesCONFIG_LINKWD_STARTCONFIG_LINKWD_ACCEPTCONFIG_LANENUM_WAITCONFIG_LANENUM_ACCEPTCONFIG_COMPLETECONFIG_IDLERecov…...
Redis 性能优化:多维度技术解析与实战策略
文章目录 1 基准性能2 使用 slowlog 优化耗时命令3 big key 优化4 使用 lazy free 特性5 缩短键值对的存储长度6 设置键值的过期时间7 禁用耗时长的查询命令8 使用 Pipeline 批量操作数据9 避免大量数据同时失效10 客户端使用优化11 限制 Redis 内存大小12 使用物理机而非虚拟机…...
QT开发技术 【基于TinyXml2的对类进行序列化和反序列化】一
一、对TinyXml2 进行封装 使用宏 实现序列化和反序列化 思路: 利用宏增加一个类函数,使用序列化器调用函数进行序列化 封装宏示例 #define XML_SERIALIZER_BEGIN(ClassName) \ public: \virtual void ToXml(XMLElement* parentElem, bool bSerialize …...
麦田物语学习笔记:创建TransitionManager控制人物场景切换
基本流程 制作场景之间的切换 1.代码思路 (1)为了实现不同场景切换,并且保持当前的persistentScene一直存在,则需要一个Manager去控制场景的加载和卸载,并且在加载每一个场景之后,都要将当前的场景Set Active Scene,保证其为激活的场景,在卸载的时候也可以方便调用当前激活的场…...
2025年最新汽车零部件企业销售项目管理解决方案
在汽车零部件企业,销售项目管理的不规范和销售预测的不准确性常导致生产计划无法及时调整,因此客户关系常常中断,导致企业业务机会的丧失。为解决该问题,企业需要投入更多资源以优化销售流程与销售预测。 1、360多维立体客户视图…...
创建基于Prism框架的WPF应用(NET Framework)项目
创建基于Prism框架的WPF应用(NET Framework)项目 1、创建WPF(NET Framework)项目并整理结构 (1)、创建WPF(NET Framework)项目; (2)、添加Views和…...
AIGC视频生成模型:Meta的Emu Video模型
大家好,这里是好评笔记,公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Meta的视频生成模型Emu Video,作为Meta发布的第二款视频生成模型,在视频生成领域发挥关键作用。 🌺优质专栏回顾&am…...
【PowerQuery专栏】PowerQuery提取XML数据
XML数据和Json 数据类型都是比较典型的层次数据类型,XML的数据格式非常的对称。所有的数据均是由标签对组成,图为典型的XML文件类型的数据。 在PowerQuery中进行XML数据类型解析采用的是Xml.Document 函数来进行文件内容的解析,Xml.Document 目前有三个可用参数。 参数1为数…...
流行的开源高性能数据同步工具 - Apache SeaTunnel 整体架构运行原理
概述 背景 数据集成在现代企业的数据治理和决策支持中扮演着至关重要的角色。随着数据源的多样化和数据量的迅速增长,企业需要具备强大的数据集成能力来高效地处理和分析数据。SeaTunnel通过其高度可扩展和灵活的架构,帮助企业快速实现多源数据的采集、…...
基于单片机的多功能蓝牙语音智能台灯(论文+源码)
1总体方案设计 通过需求分析,本设计多功能蓝牙语音智能台灯的系统框图如图2.1所示,系统架构包括主控制器STM32F103单片机、HC-06蓝牙通信模块、LU-ASR01语音识别模块、OLED液晶、LED灯、按键等器件,在使用时用户可以通过手机APP、语音识别、…...
leetcode刷题记录(七十二)——146. LRU 缓存
(一)问题描述 146. LRU 缓存 - 力扣(LeetCode)146. LRU 缓存 - 请你设计并实现一个满足 LRU (最近最少使用) 缓存 [https://baike.baidu.com/item/LRU] 约束的数据结构。实现 LRUCache 类: * LRUCache(int capacity)…...
力扣203题(3)
题目及之前的两种解法大家可以移步到这里: https://blog.csdn.net/suibiansa_/article/details/145242573?spm1001.2014.3001.5501 力扣203题—— 移除链表元素-CSDN博客 今天呢我们来写一下第三种解法: 虚拟创建一个头结点 ListNode firstnew Lis…...
网络安全:信息时代的守护者
随着互联网的快速发展,网络安全问题日益成为全球关注的焦点。无论是个人用户、企业组织还是政府部门,网络安全都已成为保障信息安全、保护隐私、确保社会秩序的基石。在这个数字化时代,如何应对复杂多变的网络安全威胁,成为了我们…...
【博客之星2024年度总评选】年度回望:我的博客之路与星光熠熠
【个人主页】Francek Chen 【人生格言】征途漫漫,惟有奋斗! 【热门专栏】大数据技术基础 | 数据仓库与数据挖掘 | Python机器学习 文章目录 前言一、个人成长与盘点(一)机缘与开端(二)收获与分享 二、年度创…...
接口自动化测试
APITEST: 接口自动化测试 目录结构介绍: conf目录:用来存放项目运行环境、执行环境相关的配置参数 testsuite目录:测试用例在此目录编写,pytest默认约定test开头的文件和方法为测试用例,不满足条件的不会被执行&#x…...
题海拾贝:力扣 138.随机链表的复制
Hello大家好!很高兴我们又见面啦!给生活添点passion,开始今天的编程之路! 我的博客:<但凡. 我的专栏:《编程之路》、《数据结构与算法之美》、《题海拾贝》 欢迎点赞,关注! 1、题…...
第7章:Python TDD测试Franc对象乘法功能
写在前面 这本书是我们老板推荐过的,我在《价值心法》的推荐书单里也看到了它。用了一段时间 Cursor 软件后,我突然思考,对于测试开发工程师来说,什么才更有价值呢?如何让 AI 工具更好地辅助自己写代码,或许…...
PyTorch基本功能与实现代码
PyTorch是一个开源的深度学习框架,提供了丰富的函数和工具,以下为其主要功能的归纳: 核心数据结构: • 张量(Tensor):类似于Numpy的ndarray,是PyTorch中基本的数据结构,…...
【2024 CSDN博客之星】技术洞察类:从DeepSeek-V3的成功,看MoE混合专家网络对深度学习算法领域的影响(MoE代码级实战)
目录 一、引言 1.1 本篇文章侧重点 1.2 技术洞察—MoE(Mixture-of-Experts,混合专家网络) 二、MoE(Mixture-of-Experts,混合专家网络) 2.1 技术原理 2.2 技术优缺点 2.3 业务代码实践 2.3.1 业务场…...
Single-Model and Any-Modality for Video Object Tracking——2024——cvpr-阅读笔记
Single-Model and Any-Modality for Video Object Tracking 摘要相关工作创新处MethodShared embeddingModal promptingRGB Tracker based on TransformerOverall ExperiimentDatasetRGB-D samples are sourced from DepthTrackRGB-T samples are extracted from LasHeRRGB-E s…...
Java中的构造器
Java中的构造器详解 1. 什么是构造器 构造器(Constructor) 是一种特殊的方法,用于在创建对象时初始化对象的状态。构造器的名字必须与类名相同,且没有返回类型,连 void 也不能使用。 2. 构造器的特点 名称与类名相同…...
Restormer: Efficient Transformer for High-Resolution Image Restoration解读
论文地址:Restormer: Efficient Transformer for High-Resolution Image Restoration。 摘要 由于卷积神经网络(CNN)在从大规模数据中学习可推广的图像先验方面表现出色,这些模型已被广泛应用于图像复原及相关任务。近年来&…...
将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(3.纯python的实惠版)
前情: 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(1.标准版)-CSDN博客 将 AzureBlob 的日志通过 Azure Event Hubs 发给 Elasticsearch(2.换掉付费的Event Hubs)-CSDN博客 python脚本实现 厉害的…...
成就与远见:2024年技术与思维的升华
个人主页:chian-ocean 前言: 2025年1月17日,2024年博客之星年度评选——创作影响力评审的入围名单公布。我很荣幸能够跻身Top 300,虽然与顶尖博主仍有一定差距,但这也为我提供了更加明确的发展方向与指引。展望崭新的2025年&…...
BGP分解实验·9——路由聚合与条件性通告(1)
路由聚合是有效控制缩减BGP路由表的方法之一,路由聚合的前提和IGP一样,需要有路由目标存在BGP表中,与IGP不同的是,BGP路由聚合可以定义按需抑制路由的能力。 实验拓扑如下所示: 现在开始把从R1的R5的基础配置先准备好…...
栈和队列(C语言)
目录 数据结构之栈 定义 实现方式 基本功能实现 1)定义,初始化栈 2)入栈 3)出栈 4)获得栈顶元素 5)获得栈中有效元素个数 6)检测栈是否为空 7)销毁栈 数据结构之队列 定义 实现方…...
Jenkins-获取build用户信息
需求: 代码发布后,将发布结果发送至相关运维同学邮箱,需要获取发布人的信息。jenkins默认是没有相关内置变量的。 需要通过插件的方式进行解决: 插件: user build vars plugin 部署后,可使用的变量&…...
大数据学习(37)- Flink运行时架构
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦ᾑ…...
opengrok_windows_多工程环境搭建
目录 多工程的目录 工程代码下载和log配置 工程的索引 工程部署 工程测试 参考列表 多工程的目录 工程代码下载和log配置 工程代码下载 在每个工程的src目录下,下载工程代码,以下载pulseaudio的代码为例。 git clone gitgithub.com…...
Python网络自动化运维---SSH模块
目录 SSH建立过程 实验环境准备 一.SSH模块 1.1.Paramiko模块 1.1.1实验代码 1.1.2代码分段讲解 1.1.3代码运行过程 1.2Netmiko模块 Netmiko模块对比paramiko模块的改进: 1.2.1实验代码 1.2.2代码分段讲解 1.2.3代码运行过程 二.Paramiko模块和Ne…...
Failed to restart nginx.service Unit nginx.service not found
当你遇到 Failed to restart nginx.service: Unit nginx.service not found 错误时,这意味着系统无法找到 Nginx 的服务单元文件。这通常是因为 Nginx 没有通过 systemd 管理,或者 Nginx 没有正确安装。 解决方法 1. 检查 Nginx 是否正确安装 首先&am…...
学习记录之原型,原型链
构造函数创建对象 Person和普通函数没有区别,之所以是构造函数在于它是通过new关键字调用的,p就是通过构造函数Person创建的实列对象 function Person(age, name) {this.age age;this.name name;}let p new Person(18, 张三);prototype prototype n…...
【Redis】5种基础数据结构介绍及应用
考察频率难度60%⭐⭐ 这个方向的问题也是非常基础的,所以一般不会直接被当做一个单独的问题。常见的形式是结合你简历上的项目或者场景题来提问,即实际应用场景、是否可以优化、如何选择等。 由于场景题和实际项目差异较大,所以本文就只做基…...
基于GRU实现股价多变量时间序列预测(PyTorch版)
前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…...
Java Web开发高级——Spring Boot与Docker容器化部署
随着云计算和微服务架构的快速发展,容器化已成为现代应用部署的重要手段。Docker作为最受欢迎的容器化技术之一,使得开发者能够将应用及其所有依赖打包到一个可移植的容器中,简化了开发、测试、部署和运维的流程。本篇文章将通过以下内容讲解…...
计算机网络——网络层
重点内容: (1) 虚拟互连网络的概念。 (2) IP 地址与物理地址的关系。 (3) 传统的分类的 IP 地址(包括子网掩码)和无分类域间路由选择 CIDR 。 (4) 路由选择协议的工作原理。 目录 重点内容: 一.网络层提供的两种服务 二…...
每打开一个chrome页面都会【自动打开F12开发者模式】,原因是 使用HBuilderX会影响谷歌浏览器的浏览模式
打开 HBuilderX,点击 运行 -> 运行到浏览器 -> 设置web服务器 -> 添加chrome浏览器安装路径 chrome谷歌浏览器插件 B站视频下载助手插件: 参考地址:Chrome插件 - B站下载助手(轻松下载bilibili哔哩哔哩视频)…...
cesium绕点旋转
绕点旋转的原理可以理解为相机一直看向一个点,不断改变相机的位置 let position Cesium.Cartesian3.fromDegrees(longitude, latitude) let lookAtTimer setInterval(() > {let heading viewer.camera.heading;let pitch viewer.camera.pitch;if (heading &…...
JavaScript系列(36)--微服务架构详解
JavaScript微服务架构详解 🏗️ 今天,让我们深入了解JavaScript的微服务架构,这是构建大规模分布式系统的关键技术。 微服务基础概念 🌟 💡 小知识:微服务架构是一种将应用程序构建为一组小型服务的方法&…...
神经网络基础 | 给定条件下推导对应的卷积层参数
神经网络基础 | 给定条件下推导对应的卷积层参数 按照 PyTorch 文档中 给定的设置: H o u t ⌊ H i n 2 padding [ 0 ] − dilation [ 0 ] ( kernel_size [ 0 ] − 1 ) − 1 stride [ 0 ] 1 ⌋ H_{out} \left\lfloor\frac{H_{in} 2 \times \text{padding}[0]…...
面向CTF的python_requests库的学习笔记
看师傅们写的各种脚本羡慕不已,自己却只会一点一点手搓,于是来做个笔记 requests库是干嘛的? 顾名思义,request就是请求,可以用来向服务器发送请求。它可以代替你在网站上发送请求报文,并接受回应报文。简…...
MIAOYUN信创云原生项目亮相西部“中试”生态对接活动
近日,以“构建‘中试’生态,赋能科技成果转化”为主题的“科创天府智汇蓉城”西部“中试”生态对接活动在成都高新区菁蓉汇隆重开幕。活动分为成果展览、“中试”生态主场以及成果路演洽谈对接三大板块。在成果展览环节,成都元来云志科技有限…...