必看知识点:Redis 中的原子操作(1)-Redis 中命令的原子性
必看知识点:Redis 中的原子操作(1)-Redis 中命令的原子性
Redis 如何应对并发访问
Redis 中处理并发的方案
业务中有时候我们会用 Redis 处理一些高并发的业务场景,例如,秒杀业务,对于库存的操作。。。
先来分析下,并发场景下会发生什么问题
并发问题主要发生在数据的修改上,对于客户端修改数据,一般分成下面两个步骤:
1、客户端先把数据读取到本地,在本地进行修改;
2、客户端修改完数据后,再写回Redis。
我们把这个流程叫做读取-修改-写回操作(Read-Modify-Write,简称为 RMW 操作)。如果客户端并发进行 RMW 操作的时候,就需要保证 读取-修改-写回是一个原子操作,进行命令操作的时候,其他客户端不能对当前的数据进行操作。
错误的栗子:
统计一个页面的访问次数,每次刷新页面访问次数+1,这里使用 Redis 来记录访问次数。
如果每次的读取-修改-写回操作不是一个原子操作,那么就可能存在下图的问题,客户端2在客户端1操作的中途,也获取 Redis 的值,也对值进行+1,操作,这样就导致最终数据的错误。
对于上面的这种情况,一般会有两种方式解决:
1、使用 Redis 实现一把分布式锁,通过锁来保护每次只有一个线程来操作临界资源;
2、实现操作命令的原子性。
- 栗如,对于上面的错误栗子,如果读取-修改-写回是一个原子性的命令,那么这个命令在操作过程中就不有别的线程同时读取操作数据,这样就能避免上面栗子出现的问题。
下面从原子性和锁两个方面,具体分析下,对并发访问问题的处理
原子性
为了实现并发控制要求的临界区代码互斥执行,如果使用 Redis 中命令的原子性,可以有下面两种处理方式:
1、借助于 Redis 中的原子性的单命令;
2、把多个操作写到一个Lua脚本中,以原子性方式执行单个Lua脚本。
在探讨 Redis 原子性的时候,先来探讨下 Redis 中使用到的编程模型
Redis 的编程模型
Redis 中使用到了 Reactor 模型,Reactor 是非阻塞 I/O 模型,这里来看下 Unix 中的 I/O 模型。
Unix 中的 I/O 模型
操作系统上的 I/O 是用户空间和内核空间的数据交互,因此 I/O 操作通常包含以下两个步骤:
1、等待网络数据到达网卡(读就绪)/等待网卡可写(写就绪) –> 读取/写入到内核缓冲区;
2、从内核缓冲区复制数据 –> 用户空间(读)/从用户空间复制数据 -> 内核缓冲区(写);
Unix 中有五种基本的 I/O 模型
- 阻塞式 I/O;
- 非阻塞式 I/O;
- I/O 多路复用;
- 信号驱动 I/O;
- 异步 I/O;
而判定一个 I/O 模型是同步还是异步,主要看第二步:数据在用户和内核空间之间复制的时候是不是会阻塞当前进程,如果会,则是同步 I/O,否则,就是异步 I/O。
这里主要分下下面三种 I/O 模型
- 阻塞型 I/O;
当用户程序执行 read ,线程会被阻塞,一直等到内核数据准备好,并把数据从内核缓冲区拷贝到应用程序的缓冲区中,当拷贝过程完成,read 才会返回。
阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。
- 非阻塞同步 I/O;
非阻塞的 read 请求在数据未准备好的情况下立即返回,可以继续往下执行,此时应用程序不断轮询内核,直到数据准备好,内核将数据拷贝到应用程序缓冲区,read 调用才可以获取到结果。
这里最后一次 read 调用,获取数据的过程,是一个同步的过程,是需要等待的过程。这里的同步指的是内核态的数据拷贝到用户程序的缓存区这个过程。
- 非阻塞异步 I/O;
发起异步 I/O,就立即返回,内核自动将数据从内核空间拷贝到用户空间,这个拷贝过程同样是异步的,内核自动完成的,和前面的同步操作不一样,应用程序并不需要主动发起拷贝动作。
举个你去饭堂吃饭的例子,你好比应用程序,饭堂好比操作系统。
阻塞 I/O 好比,你去饭堂吃饭,但是饭堂的菜还没做好,然后你就一直在那里等啊等,等了好长一段时间终于等到饭堂阿姨把菜端了出来(数据准备的过程),但是你还得继续等阿姨把菜(内核空间)打到你的饭盒里(用户空间),经历完这两个过程,你才可以离开。
非阻塞 I/O 好比,你去了饭堂,问阿姨菜做好了没有,阿姨告诉你没,你就离开了,过几十分钟,你又来饭堂问阿姨,阿姨说做好了,于是阿姨帮你把菜打到你的饭盒里,这个过程你是得等待的。
异步 I/O 好比,你让饭堂阿姨将菜做好并把菜打到饭盒里后,把饭盒送到你面前,整个过程你都不需要任何等待。
在 web 服务中,处理 web 请求通常有两种体系结构,分别为:thread-based architecture(基于线程的架构)、event-driven architecture(事件驱动模型)
thread-based architecture(基于线程的架构)
thread-based architecture(基于线程的架构):这种比较容易理解,就是多线程并发模式,服务端在处理请求的时候,一个请求分配一个独立的线程来处理。
因为每个请求分配一个独立的线程,所以单个线程的阻塞不会影响到其他的线程,能够提高程序的响应速度。
不足的是,连接和线程之间始终保持一对一的关系,如果是一直处于 Keep-Alive 状态的长连接将会导致大量工作线程在空闲状态下等待,例如,文件系统访问,网络等。此外,成百上千的连接还可能会导致并发线程浪费大量内存的堆栈空间。
event-driven architecture(事件驱动模型)
事件驱动的体系结构由事件生产者和事件消费者组,是一种松耦合、分布式的驱动架构,生产者收集到某应用产生的事件后实时对事件采取必要的处理后路由至下游系统,无需等待系统响应,下游的事件消费者组收到是事件消息,异步的处理。
事件驱动架构具有以下优势:
- 降低耦合;
降低事件生产者和订阅者的耦合性。事件生产者只需关注事件的发生,无需关注事件如何处理以及被分发给哪些订阅者。任何一个环节出现故障,不会影响其他业务正常运行。
- 异步执行;
事件驱动架构适用于异步场景,即便是需求高峰期,收集各种来源的事件后保留在事件总线中,然后逐步分发传递事件,不会造成系统拥塞或资源过剩的情况。
- 可扩展性;
事件驱动架构中路由和过滤能力支持划分服务,便于扩展和路由分发。
Reactor 模式和 Proactor 模式都是 event-driven architecture(事件驱动模型)的实现方式,这里具体分析下
Reactor 模式
Reactor 模式,是指通过一个或多个输入同时传递给服务处理器的服务请求的事件驱动处理模式。
在处理⽹络 IO 的连接事件、读事件、写事件。Reactor 中引入了三类角色
- reactor:监听和分配事件,连接事件交给 acceptor 处理,读写事件交给 handler 处理;
- acceptor:接收连接请求,接收连接后,会创建 handler ,处理网络连接上对后续读写事件的处理;
- handler:处理读写事件。
Reactor 模型又分为 3 类:
- 单线程 Reactor 模式;
建立连接(Acceptor)、监听accept、read、write事件(Reactor)、处理事件(Handler)都只用一个单线程;
- 多线程 Reactor 模式;
与单线程模式不同的是,添加了一个工作者线程池,并将非 I/O 操作从 Reactor 线程中移出转交给工作者线程池(Thread Pool)来执行。
建立连接(Acceptor)和 监听accept、read、write事件(Reactor),复用一个线程。
工作线程池:处理事件(Handler),由一个工作线程池来执行业务逻辑,包括数据就绪后,用户态的数据读写。
- 主从 Reactor 模式;
对于多个CPU的机器,为充分利用系统资源,将 Reactor 拆分为两部分:mainReactor 和 subReactor。
mainReactor:负责监听server socket,用来处理网络新连接的建立,将建立的socketChannel指定注册给subReactor,通常一个线程就可以处理;
subReactor:监听accept、read、write事件(Reactor),包括等待数据就绪时,内核态的数据读写,通常使用多线程。
工作线程:处理事件(Handler)可以和 subReactor 共同使用同一个线程,也可以做成线程池,类似上面多线程 Reactor 模式下的工作线程池的处理方式。
Proactor 模式
reactor 流程与 Reactor 模式类似
不同点就是
- Reactor 是非阻塞同步网络模式,感知的是就绪可读写事件。
在每次感知到有事件发生(比如可读就绪事件)后,就需要应用进程主动调用 read 方法来完成数据的读取,也就是要应用进程主动将 socket 接收缓存中的数据读到应用进程内存中,这个过程是同步的,读取完数据后应用进程才能处理数据。
- Proactor 是异步网络模式,感知的是已完成的读写事件。
在发起异步读写请求时,需要传入数据缓冲区的地址(用来存放结果数据)等信息,这样系统内核才可以自动帮我们把数据的读写工作完成,这里的读写工作全程由操作系统来做,并不需要像 Reactor 那样还需要应用进程主动发起 read/write 来读写数据,操作系统完成读写工作后,就会通知应用进程直接处理数据。
因此,Reactor 可以理解为「来了事件操作系统通知应用进程,让应用进程来处理」,而 Proactor 可以理解为「来了事件操作系统来处理,处理完再通知应用进程」。
举个实际生活中的例子,Reactor 模式就是快递员在楼下,给你打电话告诉你快递到你家小区了,你需要自己下楼来拿快递。而在 Proactor 模式下,快递员直接将快递送到你家门口,然后通知你。
为什么 Redis 选择单线程
Redis 中使用是单线程,可能处于以下几方面的考虑
1、Redis 是纯内存的操作,执行速度是非常快的,因此这部分操作通常不会是性能瓶颈,性能瓶颈在于网络 I/O;
2、避免过多的上下文切换开销,单线程则可以规避进程内频繁的线程切换开销;
3、避免同步机制的开销,多线程必然会面临对于共享资源的访问,这时候通常的做法就是加锁,虽然是多线程,这时候就会变成串行的访问。也就是多线程编程模式会面临的共享资源的并发访问控制问题;
4、简单可维护,多线程也会引入同步原语来保护共享资源的并发访问,代码的可维护性和易读性将会下降。
Redis 在 v6.0 版本之前,Redis 的核心网络模型一直是一个典型的单 Reactor 模型:利用 epoll/select/kqueue 等多路复用技术,在单线程的事件循环中不断去处理事件(客户端请求),最后回写响应数据到客户端:
这里来看下 Redis 如何使用单线程处理任务
事件驱动框架对事件的捕获分发
Redis 的网络框架实现了 Reactor 模型,并且自行开发实现了一个事件驱动框架。
事件驱动框架的逻辑简单点讲就是
- 事件初始化;
- 事件捕获;
- 分发和处理主循环。
来看下 Redis 中事件驱动框架实现的几个主要函数
// 执行事件捕获,分发和处理循环
void aeMain(aeEventLoop *eventLoop);
// 用来注册监听的事件和事件对应的处理函数。只有对事件和处理函数进行了注册,才能在事件发生时调用相应的函数进行处理。
int aeCreateFileEvent(aeEventLoop *eventLoop, int fd, int mask, aeFileProc *proc, void *clientData);
// aeProcessEvents 函数实现的主要功能,包括捕获事件、判断事件类型和调用具体的事件处理函数,从而实现事件的处理
int aeProcessEvents(aeEventLoop *eventLoop, int flags);
使用 aeMain 作为主循环来对事件进行持续监听和捕获,其中会调用 aeProcessEvents 函数,实现事件捕获、判断事件类型和调用具体的事件处理函数,从而实现事件的处理。
// https://github.com/redis/redis/blob/5.0/src/ae.c#L496
void aeMain(aeEventLoop *eventLoop) {eventLoop->stop = 0;while (!eventLoop->stop) {if (eventLoop->beforesleep != NULL)eventLoop->beforesleep(eventLoop);aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);}
}// https://github.com/redis/redis/blob/5.0/src/ae.c#L358
int aeProcessEvents(aeEventLoop *eventLoop, int flags)
{...if (eventLoop->maxfd != -1 || ((flags & AE_TIME_EVENTS) && !(flags & AE_DONT_WAIT))) {...//调用aeApiPoll函数捕获事件numevents = aeApiPoll(eventLoop, tvp);...}...
}
可以看到 aeProcessEvents 中对于 IO 事件的捕获是通过调用 aeApiPoll 来完成的。
aeApiPoll 是 I/O 多路复用 API,是基于 epoll_wait/select/kevent 等系统调用的封装,监听等待读写事件触发,然后处理,它是事件循环(Event Loop)中的核心函数,是事件驱动得以运行的基础。
Redis 是依赖于操作系统底层提供的 IO 多路复用机制,来实现事件捕获,检查是否有新的连接、读写事件发生。为了适配不同的操作系统,Redis 对不同操作系统实现的网络 IO 多路复用函数,都进行了统一的封装。
// https://github.com/redis/redis/blob/5.0/src/ae.c#L49
#ifdef HAVE_EVPORT
#include "ae_evport.c" // Solaris
#else#ifdef HAVE_EPOLL#include "ae_epoll.c" // Linux#else#ifdef HAVE_KQUEUE#include "ae_kqueue.c" // MacOS#else#include "ae_select.c" // Windows#endif#endif
#endif
ae_epoll.c:对应 Linux 上的 IO 复用函数 epoll;
ae_evport.c:对应 Solaris 上的 IO 复用函数 evport;
ae_kqueue.c:对应 macOS 或 FreeBSD 上的 IO 复用函数 kqueue;
ae_select.c:对应 Linux(或 Windows)的 IO 复用函数 select。
客户端连接应答
监听 socket 的读事件,当有客户端连接请求过来,使用函数 acceptTcpHandler 和客户端建立连接
当 Redis 启动后,服务器程序的 main 函数会调用 initSever 函数来进行初始化,而在初始化的过程中,aeCreateFileEvent 就会被 initServer 函数调用,用于注册要监听的事件,以及相应的事件处理函数。
// https://github.com/redis/redis/blob/5.0/src/server.c#L2036
void initServer(void) {...// 创建一个事件处理程序以接受 TCP 和 Unix 中的新连接for (j = 0; j < server.ipfd_count; j++) {if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,acceptTcpHandler,NULL) == AE_ERR){serverPanic("Unrecoverable error creating server.ipfd file event.");}}...
}
可以看到 initServer 中会根据启用的 IP 端口个数,为每个 IP 端口上的网络事件,调用 aeCreateFileEvent,创建对 AE_READABLE 事件的监听,并且注册 AE_READABLE 事件的处理 handler,也就是 acceptTcpHandler 函数。
然后看下 acceptTcpHandler 的实现
// https://github.com/redis/redis/blob/5.0/src/networking.c#L734
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {int cport, cfd, max = MAX_ACCEPTS_PER_CALL;char cip[NET_IP_STR_LEN];UNUSED(el);UNUSED(mask);UNUSED(privdata);while(max--) {// 用于accept客户端的连接,其返回值是客户端对应的socketcfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);if (cfd == ANET_ERR) {if (errno != EWOULDBLOCK)serverLog(LL_WARNING,"Accepting client connection: %s", server.neterr);return;}serverLog(LL_VERBOSE,"Accepted %s:%d", cip, cport);// 会调用acceptCommonHandler对连接以及客户端进行初始化acceptCommonHandler(cfd,0,cip);}
}// https://github.com/redis/redis/blob/5.0/src/networking.c#L664
static void acceptCommonHandler(int fd, int flags, char *ip) {client *c;// 分配并初始化新客户端if ((c = createClient(fd)) == NULL) {serverLog(LL_WARNING,"Error registering fd event for the new client: %s (fd=%d)",strerror(errno),fd);close(fd); /* May be already closed, just ignore errors */return;}// 判断当前连接的客户端是否超过最大值,如果超过的话,会拒绝这次连接。否则,更新客户端连接数的计数if (listLength(server.clients) > server.maxclients) {char *err = "-ERR max number of clients reached\r\n";/* That's a best effort error message, don't check write errors */if (write(c->fd,err,strlen(err)) == -1) {/* Nothing to do, Just to avoid the warning... */}server.stat_rejected_conn++;freeClient(c);return;}...
}// 使用多路复用,需要记录每个客户端的状态,client 之前通过链表保存
typedef struct client {
int fd; // 字段是客户端套接字文件描述符
sds querybuf; // 保存客户端发来命令请求的输入缓冲区。以Redis通信协议的方式保存
int argc; // 当前命令的参数数量
robj **argv; // 当前命令的参数
redisDb *db; // 当前选择的数据库指针
int flags;
list *reply; // 保存命令回复的链表。因为静态缓冲区大小固定,主要保存固定长度的命令回复,当处理一些返回大量回复的命令,则会将命令回复以链表的形式连接起来。
// ... many other fields ...
char buf[PROTO_REPLY_CHUNK_BYTES];
} client;client *createClient(int fd) {client *c = zmalloc(sizeof(client));// 如果fd为-1,表示创建的是一个无网络连接的伪客户端,用于执行lua脚本的时候。// 如果fd不等于-1,表示创建一个有网络连接的客户端if (fd != -1) {// 设置fd为非阻塞模式anetNonBlock(NULL,fd);// 禁止使用 Nagle 算法,client向内核递交的每个数据包都会立即发送给server出去,TCP_NODELAYanetEnableTcpNoDelay(NULL,fd);// 如果开启了tcpkeepalive,则设置 SO_KEEPALIVEif (server.tcpkeepalive)anetKeepAlive(NULL,fd,server.tcpkeepalive);// 创建一个文件事件状态el,且监听读事件,开始接受命令的输入if (aeCreateFileEvent(server.el,fd,AE_READABLE,readQueryFromClient, c) == AE_ERR){close(fd);zfree(c);return NULL;}}...// 初始化client 中的参数return c;
}
1、acceptTcpHandler 主要用于处理和客户端连接的建立;
2、其中会调用函数 anetTcpAccept 用于 accept 客户端的连接,其返回值是客户端对应的 socket;
3、然后调用 acceptCommonHandler 对连接以及客户端进行初始化;
4、初始化客户端的时候,同时使用 aeCreateFileEvent 用来注册监听的事件和事件对应的处理函数,将 readQueryFromClient 命令读取处理器绑定到新连接对应的文件描述符上;
5、服务器会监听该文件描述符的读事件,当客户端发送了命令,触发了 AE_READABLE 事件,那么就会调用回调函数 readQueryFromClient() 来从文件描述符 fd 中读发来的命令,并保存在输入缓冲区中 querybuf。
命令的接收
readQueryFromClient 是请求处理的起点,解析并执行客户端的请求命令。
// https://github.com/redis/redis/blob/5.0/src/networking.c#L1522
// 读取client的输入缓冲区的内容
void readQueryFromClient(aeEventLoop *el, int fd, void *privdata, int mask) {client *c = (client*) privdata;int nread, readlen;size_t qblen;UNUSED(el);UNUSED(mask);...// 输入缓冲区的长度qblen = sdslen(c->querybuf);// 更新缓冲区的峰值if (c->querybuf_peak < qblen) c->querybuf_peak = qblen;// 扩展缓冲区的大小c->querybuf = sdsMakeRoomFor(c->querybuf, readlen);// 调用read从描述符为fd的客户端socket中读取数据nread = read(fd, c->querybuf+qblen, readlen);...// 处理读取的内容processInputBufferAndReplicate(c);
}
// https://github.com/redis/redis/blob/5.0/src/networking.c#L1507
void processInputBufferAndReplicate(client *c) {// 当前客户端不属于主从复制中的Master // 直接调用 processInputBuffer,对客户端输入缓冲区中的命令和参数进行解析if (!(c->flags & CLIENT_MASTER)) {processInputBuffer(c);// 客户端属于主从复制中的Master // 调用processInputBuffer函数,解析客户端命令, // 调用replicationFeedSlavesFromMasterStream 函数,将主节点接收到的命令同步给从节点} else {size_t prev_offset = c->reploff;processInputBuffer(c);size_t applied = c->reploff - prev_offset;if (applied) {replicationFeedSlavesFromMasterStream(server.slaves,c->pending_querybuf, applied);sdsrange(c->pending_querybuf,applied,-1);}}
}// https://github.com/redis/redis/blob/5.0/src/networking.c#L1428
void processInputBuffer(client *c) {server.current_client = c;/* Keep processing while there is something in the input buffer */// 持续读取缓冲区的内容while(c->qb_pos < sdslen(c->querybuf)) {.../* Multibulk processing could see a <= 0 length. */// 如果参数为0,则重置clientif (c->argc == 0) {resetClient(c);} else {/* Only reset the client when the command was executed. */// 执行命令成功后重置clientif (processCommand(c) == C_OK) {if (c->flags & CLIENT_MASTER && !(c->flags & CLIENT_MULTI)) {/* Update the applied replication offset of our master. */c->reploff = c->read_reploff - sdslen(c->querybuf) + c->qb_pos;}// 命令处于阻塞状态中的客户端,不需要进行重置if (!(c->flags & CLIENT_BLOCKED) || c->btype != BLOCKED_MODULE)resetClient(c);}/* freeMemoryIfNeeded may flush slave output buffers. This may* result into a slave, that may be the active client, to be* freed. */if (server.current_client == NULL) break;}}/* Trim to pos */if (server.current_client != NULL && c->qb_pos) {sdsrange(c->querybuf,c->qb_pos,-1);c->qb_pos = 0;}server.current_client = NULL;
}
1、readQueryFromClient(),从文件描述符 fd 中读出数据到输入缓冲区 querybuf 中;
2、使用 processInputBuffer 函数完成对命令的解析,在其中使用 processInlineBuffer 或者 processMultibulkBuffer 根据 Redis 协议解析命令;
3、完成对一个命令的解析,就使用 processCommand 对命令就行执行;
4、命令执行完成,最后调用 addReply 函数族的一系列函数将响应数据写入到对应 client 的写出缓冲区:client->buf 或者 client->reply ,client->buf 是首选的写出缓冲区,固定大小 16KB,一般来说可以缓冲足够多的响应数据,但是如果客户端在时间窗口内需要响应的数据非常大,那么则会自动切换到 client->reply 链表上去,使用链表理论上能够保存无限大的数据(受限于机器的物理内存),最后把 client 添加进一个 LIFO 队列 clients_pending_write;
命令的回复
在 Redis 事件驱动框架每次循环进入事件处理函数前,来处理监听到的已触发事件或是到时的时间事件之前,都会调用 beforeSleep 函数,进行一些任务处理,这其中就包括了调用
handleClientsWithPendingWrites 函数,它会将 Redis sever 客户端缓冲区中的数据写回客户端。
// https://github.com/redis/redis/blob/5.0/src/server.c#L1380
void beforeSleep(struct aeEventLoop *eventLoop) {UNUSED(eventLoop);...// 将 Redis sever 客户端缓冲区中的数据写回客户端handleClientsWithPendingWrites();...
}// https://github.com/redis/redis/blob/5.0/src/networking.c#L1082
int handleClientsWithPendingWrites(void) {listIter li;listNode *ln;// 遍历 clients_pending_write 队列,调用 writeToClient 把 client 的写出缓冲区里的数据回写到客户端int processed = listLength(server.clients_pending_write);listRewind(server.clients_pending_write,&li);while((ln = listNext(&li))) {client *c = listNodeValue(ln);c->flags &= ~CLIENT_PENDING_WRITE;listDelNode(server.clients_pending_write,ln);...// 调用 writeToClient 函数,将客户端输出缓冲区中的数据写回if (writeToClient(c->fd,c,0) == C_ERR) continue;// 如果输出缓冲区的数据还没有写完,此时,handleClientsWithPendingWrites 函数就// 会调用 aeCreateFileEvent 函数,创建可写事件,并设置回调函数 sendReplyToClienif (clientHasPendingReplies(c)) {int ae_flags = AE_WRITABLE;if (server.aof_state == AOF_ON &&server.aof_fsync == AOF_FSYNC_ALWAYS){ae_flags |= AE_BARRIER;}// 将文件描述符fd和AE_WRITABLE事件关联起来,当客户端可写时,就会触发事件,调用sendReplyToClient()函数,执行写事件if (aeCreateFileEvent(server.el, c->fd, ae_flags,sendReplyToClient, c) == AE_ERR){freeClientAsync(c);}}}return processed;
}// https://github.com/redis/redis/blob/5.0/src/networking.c#L1072
// 写事件处理程序,只是发送回复给client
void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {UNUSED(el);UNUSED(mask);writeToClient(fd,privdata,1);
}// https://github.com/redis/redis/blob/5.0/src/networking.c#L979
// 将输出缓冲区的数据写给client,如果client被释放则返回C_ERR,没被释放则返回C_OK
int writeToClient(int fd, client *c, int handler_installed) {ssize_t nwritten = 0, totwritten = 0;size_t objlen;clientReplyBlock *o;// 如果指定的client的回复缓冲区中还有数据,则返回真,表示可以写socketwhile(clientHasPendingReplies(c)) {// 固定缓冲区发送未完成if (c->bufpos > 0) {// 将缓冲区的数据写到fd中nwritten = write(fd,c->buf+c->sentlen,c->bufpos-c->sentlen);...// 如果发送的数据等于buf的偏移量,表示发送完成if ((int)c->sentlen == c->bufpos) {c->bufpos = 0;c->sentlen = 0;}// 固定缓冲区发送完成,发送回复链表的内容} else {// 回复链表的第一条回复对象,和对象值的长度和所占的内存o = listNodeValue(listFirst(c->reply));objlen = o->used;if (objlen == 0) {c->reply_bytes -= o->size;listDelNode(c->reply,listFirst(c->reply));continue;}// 将当前节点的值写到fd中nwritten = write(fd, o->buf + c->sentlen, objlen - c->sentlen);if (nwritten <= 0) break;c->sentlen += nwritten;totwritten += nwritten;...}...}...// 如果指定的client的回复缓冲区中已经没有数据,发送完成if (!clientHasPendingReplies(c)) {c->sentlen = 0;// 删除当前client的可读事件的监听if (handler_installed) aeDeleteFileEvent(server.el,c->fd,AE_WRITABLE);/* Close connection after entire reply has been sent. */// 如果指定了写入按成之后立即关闭的标志,则释放clientif (c->flags & CLIENT_CLOSE_AFTER_REPLY) {freeClient(c);return C_ERR;}}return C_OK;
}
1、beforeSleep 函数调用的
handleClientsWithPendingWrites 函数,会遍历 clients_pending_write(待写回数据的客户端) 队列,调用 writeToClient 把 client 的写出缓冲区里的数据回写到客户端,然后调用 writeToClient 函数,将客户端输出缓冲区中的数据发送给客户端;
2、如果输出缓冲区的数据还没有写完,此时,
handleClientsWithPendingWrites 函数就会调用 aeCreateFileEvent 函数,注册 sendReplyToClient 到该连接的写就绪事件,等待将后续将数据写回给客户端。
上面的执行流程总结下来就是
1、Redis Server 启动后,主线程会启动一个时间循环(Event Loop),持续监听事件;
2、client 到 server 的新连接,会调用 acceptTcpHandler 函数,之后会注册读事件 readQueryFromClient 函数,client 发给 server 的数据,都会在这个函数处理,这个函数会解析 client 的数据,找到对应的 cmd 函数执行;
3、cmd 逻辑执行完成后,server 需要写回数据给 client,调用 addReply 函数族的一系列函数将响应数据写入到对应 client 的写出缓冲区:client->buf 或者 client->reply ,client->buf 是首选的写出缓冲区,固定大小 16KB,一般来说可以缓冲足够多的响应数据,但是如果客户端在时间窗口内需要响应的数据非常大,那么则会自动切换到 client->reply 链表上去,使用链表理论上能够保存无限大的数据(受限于机器的物理内存),最后把 client 添加进一个 LIFO 队列 clients_pending_write;
4、在 Redis 事件驱动框架每次循环进入事件处理函数前,来处理监听到的已触发事件或是到时的时间事件之前,都会调用 beforeSleep 函数,进行一些任务处理,这其中就包括了调用
handleClientsWithPendingWrites 函数,它会将 Redis sever 客户端缓冲区中的数据写回客户端;
- beforeSleep 函数调用的 handleClientsWithPendingWrites 函数,会遍历 clients_pending_write(待写回数据的客户端) 队列,调用 writeToClient 把 client 的写出缓冲区里的数据回写到客户端,然后调用 writeToClient 函数,将客户端输出缓冲区中的数据发送给客户端;
- 如果输出缓冲区的数据还没有写完,此时,handleClientsWithPendingWrites 函数就会调用 aeCreateFileEvent 函数,注册 sendReplyToClient 到该连接的写就绪事件,等待将后续将数据写回给客户端。
Redis 多IO线程
在 Redis6.0 的版本中,引入了多线程来处理 IO 任务,多线程的引入,充分利用了当前服务器多核特性,使用多核运行多线程,让多线程帮助加速数据读取、命令解析以及数据写回的速度,提升 Redis 整体性能。
Redis6.0 之前的版本用的是单线程 Reactor 模式,所有的操作都在一个线程中完成,6.0 之后的版本使用了主从 Reactor 模式。
由一个 mainReactor 线程接收连接,然后发送给多个 subReactor 线程处理,subReactor 负责处理具体的业务。
来看下 Redis 多IO线程的具体实现过程
多 IO 线程的初始化
使用 initThreadedIO 函数来初始化多 IO 线程。
// https://github.com/redis/redis/blob/6.2/src/networking.c#L3573
void initThreadedIO(void) {server.io_threads_active = 0; /* We start with threads not active. *//* Don't spawn any thread if the user selected a single thread:* we'll handle I/O directly from the main thread. */// 如果用户只配置了一个 I/O 线程,不需要创建新线程了,直接在主线程中处理if (server.io_threads_num == 1) return;if (server.io_threads_num > IO_THREADS_MAX_NUM) {serverLog(LL_WARNING,"Fatal: too many I/O threads configured. ""The maximum number is %d.", IO_THREADS_MAX_NUM);exit(1);}/* Spawn and initialize the I/O threads. */// 初始化线程for (int i = 0; i < server.io_threads_num; i++) {/* Things we do for all the threads including the main thread. */io_threads_list[i] = listCreate();// 编号为0是主线程if (i == 0) continue; /* Thread 0 is the main thread. *//* Things we do only for the additional threads. */pthread_t tid;// 初始化io_threads_mutex数组pthread_mutex_init(&io_threads_mutex[i],NULL);// 初始化io_threads_pending数组setIOPendingCount(i, 0);// 主线程在启动 I/O 线程的时候会默认先锁住它,直到有 I/O 任务才唤醒它。pthread_mutex_lock(&io_threads_mutex[i]); /* Thread will be stopped. */// 调用pthread_create函数创建IO线程,线程运行函数为IOThreadMainif (pthread_create(&tid,NULL,IOThreadMain,(void*)(long)i) != 0) {serverLog(LL_WARNING,"Fatal: Can't initialize IO thread.");exit(1);}io_threads[i] = tid;}
}
可以看到在 initThreadedIO 中完成了对下面四个数组的初始化工作
io_threads_list 数组:保存了每个 IO 线程要处理的客户端,将数组每个元素初始化为一个 List 类型的列表;
io_threads_pending 数组:保存等待每个 IO 线程处理的客户端个数;
io_threads_mutex 数组:保存线程互斥锁;
io_threads 数组:保存每个 IO 线程的描述符。
命令的接收
Redis server 在和一个客户端建立连接后,就开始了监听客户端的可读事件,处理可读事件的回调函数就是 readQueryFromClient。
// https://github.com/redis/redis/blob/6.2/src/networking.c#L2219
void readQueryFromClient(connection *conn) {client *c = connGetPrivateData(conn);int nread, readlen;size_t qblen;/* Check if we want to read from the client later when exiting from* the event loop. This is the case if threaded I/O is enabled. */// 判断是否从客户端延迟读取数据if (postponeClientRead(c)) return;...
}// https://github.com/redis/redis/blob/6.2/src/networking.c#L3746
int postponeClientRead(client *c) {// 当多线程 I/O 模式开启、主线程没有在处理阻塞任务时,将 client 加入异步队列。if (server.io_threads_active &&server.io_threads_do_reads &&!ProcessingEventsWhileBlocked &&!(c->flags & (CLIENT_MASTER|CLIENT_SLAVE|CLIENT_PENDING_READ|CLIENT_BLOCKED))) {// 给客户端的flag添加CLIENT_PENDING_READ标记,表示推迟该客户端的读操作c->flags |= CLIENT_PENDING_READ;// 将可获得加入clients_pending_write列表listAddNodeHead(server.clients_pending_read,c);return 1;} else {return 0;}
}
使用 clients_pending_read 保存了需要进行延迟读操作的客户端之后,这些客户端又是如何分配给多 IO 线程执行的呢?
handleClientsWithPendingWritesUsingThreads 函数:该函数主要负责将 clients_pending_write 列表中的客户端分配给 IO 线程进行处理。
看下如何实现
// https://github.com/redis/redis/blob/6.2/src/networking.c#L3766
int handleClientsWithPendingReadsUsingThreads(void) {// 当多线程 I/O 模式开启,才能执行下面的流程if (!server.io_threads_active || !server.io_threads_do_reads) return 0;int processed = listLength(server.clients_pending_read);if (processed == 0) return 0;// 遍历待读取的 client 队列 clients_pending_read,// 根据IO线程的数量,让clients_pending_read中客户端数量对IO线程进行取模运算// 取模的结果就是客户端分配给对应IO线程的编号listIter li;listNode *ln;listRewind(server.clients_pending_read,&li);int item_id = 0;while((ln = listNext(&li))) {client *c = listNodeValue(ln);int target_id = item_id % server.io_threads_num;listAddNodeTail(io_threads_list[target_id],c);item_id++;}// 设置当前 I/O 操作为读取操作,给每个 I/O 线程的计数器设置分配的任务数量,// 让 I/O 线程可以开始工作:只读取和解析命令,不执行io_threads_op = IO_THREADS_OP_READ;for (int j = 1; j < server.io_threads_num; j++) {int count = listLength(io_threads_list[j]);setIOPendingCount(j, count);}// 主线程自己也会去执行读取客户端请求命令的任务,以达到最大限度利用 CPU。listRewind(io_threads_list[0],&li);while((ln = listNext(&li))) {client *c = listNodeValue(ln);readQueryFromClient(c->conn);}listEmpty(io_threads_list[0]);// 忙轮询,等待所有 IO 线程完成待读客户端的处理while(1) {unsigned long pending = 0;for (int j = 1; j < server.io_threads_num; j++)pending += getIOPendingCount(j);if (pending == 0) break;}// 遍历待读取的 client 队列,清除 CLIENT_PENDING_READ标记,// 然后解析并执行所有 client 的命令。while(listLength(server.clients_pending_read)) {ln = listFirst(server.clients_pending_read);client *c = listNodeValue(ln);c->flags &= ~CLIENT_PENDING_READ;listDelNode(server.clients_pending_read,ln);serverAssert(!(c->flags & CLIENT_BLOCKED));// client 的第一条命令已经被解析好了,直接尝试执行。if (processPendingCommandsAndResetClient(c) == C_ERR) {/* If the client is no longer valid, we avoid* processing the client later. So we just go* to the next. */continue;}// 解析并执行 client 命令processInputBuffer(c);// 命令执行完成之后,如果 client 中有响应数据需要回写到客户端,则将 client 加入到待写出队列 clients_pending_writeif (!(c->flags & CLIENT_PENDING_WRITE) && clientHasPendingReplies(c))clientInstallWriteHandler(c);}/* Update processed count on server */server.stat_io_reads_processed += processed;return processed;
}
1、当客户端发送命令请求之后,会触发 Redis 主线程的事件循环,命令处理器 readQueryFromClient 被回调,多线程模式下,则会把 client 加入到 clients_pending_read 任务队列中去,后面主线程再分配到 I/O 线程去读取客户端请求命令;
2、主线程会根据 clients_pending_read 中客户端数量对IO线程进行取模运算,取模的结果就是客户端分配给对应IO线程的编号;
3、忙轮询,等待所有的线程完成读取客户端命令的操作,这一步用到了多线程的请求;
4、遍历 clients_pending_read,执行所有 client 的命令,这里就是在主线程中执行的,命令的执行是单线程的操作。
命令的回复
完成命令的读取、解析以及执行之后,客户端命令的响应数据已经存入 client->buf 或者 client->reply 中。
主循环在捕获 IO 事件的时候,beforeSleep 函数会被调用,进而调用
handleClientsWithPendingWritesUsingThreads ,写回响应数据给客户端。
// https://github.com/redis/redis/blob/6.2/src/networking.c#L3662
int handleClientsWithPendingWritesUsingThreads(void) {int processed = listLength(server.clients_pending_write);if (processed == 0) return 0; /* Return ASAP if there are no clients. */// 如果用户设置的 I/O 线程数等于 1 或者当前 clients_pending_write 队列中待写出的 client// 数量不足 I/O 线程数的两倍,则不用多线程的逻辑,让所有 I/O 线程进入休眠,// 直接在主线程把所有 client 的相应数据回写到客户端。if (server.io_threads_num == 1 || stopThreadedIOIfNeeded()) {return handleClientsWithPendingWrites();}// 唤醒正在休眠的 I/O 线程(如果有的话)。if (!server.io_threads_active) startThreadedIO();/* Distribute the clients across N different lists. */// 和上面的handleClientsWithPendingReadsUsingThreads中的操作一样分配客户端给IO线程listIter li;listNode *ln;listRewind(server.clients_pending_write,&li);int item_id = 0;while((ln = listNext(&li))) {client *c = listNodeValue(ln);c->flags &= ~CLIENT_PENDING_WRITE;/* Remove clients from the list of pending writes since* they are going to be closed ASAP. */if (c->flags & CLIENT_CLOSE_ASAP) {listDelNode(server.clients_pending_write, ln);continue;}int target_id = item_id % server.io_threads_num;listAddNodeTail(io_threads_list[target_id],c);item_id++;}// 设置当前 I/O 操作为写出操作,给每个 I/O 线程的计数器设置分配的任务数量,// 让 I/O 线程可以开始工作,把写出缓冲区(client->buf 或 c->reply)中的响应数据回写到客户端。// 可以看到写回操作也是多线程执行的io_threads_op = IO_THREADS_OP_WRITE;for (int j = 1; j < server.io_threads_num; j++) {int count = listLength(io_threads_list[j]);setIOPendingCount(j, count);}// 主线程自己也会去执行读取客户端请求命令的任务,以达到最大限度利用 CPU。listRewind(io_threads_list[0],&li);while((ln = listNext(&li))) {client *c = listNodeValue(ln);writeToClient(c,0);}listEmpty(io_threads_list[0]);/* Wait for all the other threads to end their work. */// 等待所有的线程完成对应的工作while(1) {unsigned long pending = 0;for (int j = 1; j < server.io_threads_num; j++)pending += getIOPendingCount(j);if (pending == 0) break;}// 最后再遍历一次 clients_pending_write 队列,检查是否还有 client 的写出缓冲区中有残留数据,// 如果有,那就为 client 注册一个命令回复器 sendReplyToClient,等待客户端写就绪再继续把数据回写。listRewind(server.clients_pending_write,&li);while((ln = listNext(&li))) {client *c = listNodeValue(ln);// 检查 client 的写出缓冲区是否还有遗留数据。if (clientHasPendingReplies(c) &&connSetWriteHandler(c->conn, sendReplyToClient) == AE_ERR){freeClientAsync(c);}}listEmpty(server.clients_pending_write);/* Update processed count on server */server.stat_io_writes_processed += processed;return processed;
}
1、也是会将 client 分配给所有的 IO 线程;
2、忙轮询,等待所有的线程将缓存中的数据写回给客户端,这里写回操作使用的多线程;
3、最后再遍历 clients_pending_write,为那些还残留有响应数据的 client 注册命令回复处理器 sendReplyToClient,等待客户端可写之后在事件循环中继续回写残余的响应数据。
通过上面的分析可以得出结论,Redis 多IO线程中多线程的应用
1、解析客户端的命令的时候用到了多线程,但是对于客户端命令的执行,使用的还是单线程;
2、给客户端回复数据的时候,使用到了多线程。
来总结下 Redis 中多线程的执行过程
1、Redis Server 启动后,主线程会启动一个时间循环(Event Loop),持续监听事件;
2、client 到 server 的新连接,会调用 acceptTcpHandler 函数,之后会注册读事件 readQueryFromClient 函数,client 发给 server 的数据,都会在这个函数处理;
3、客户端发送给服务端的数据,不会类似 6.0 之前的版本使用 socket 直接去读,而是会将 client 放入到 clients_pending_read 中,里面保存了需要进行延迟读操作的客户端;
4、处理 clients_pending_read 的函数
handleClientsWithPendingReadsUsingThreads,在每次事件循环的时候都会调用;
- 1、主线程会根据 clients_pending_read 中客户端数量对IO线程进行取模运算,取模的结果就是客户端分配给对应IO线程的编号;
- 2、忙轮询,等待所有的线程完成读取客户端命令的操作,这一步用到了多线程的请求;
- 3、遍历 clients_pending_read,执行所有 client 的命令,这里就是在主线程中执行的,命令的执行是单线程的操作。
5、命令执行完成以后,回复的内容还是会被写入到 client 的缓存区中,这些 client 和6.0之前的版本处理方式一样,也是会被放入到 clients_pending_write(待写回数据的客户端);
6、6.0 对于clients_pending_write 的处理使用到了多线程;
- 1、也是会将 client 分配给所有的 IO 线程;
- 2、忙轮询,等待所有的线程将缓存中的数据写回给客户端,这里写回操作使用的多线程;
- 3、最后再遍历 clients_pending_write,为那些还残留有响应数据的 client 注册命令回复处理器 sendReplyToClient,等待客户端可写之后在事件循环中继续回写残余的响应数据。
原子性的单命令
通过上面的分析,我们知道,Redis 的主线程是单线程执行的,所有 Redis 中的单命令,都是原子性的。
所以对于一些场景的操作尽量去使用 Redis 中单命令去完成,就能保证命令执行的原子性。
比如对于上面的读取-修改-写回操作可以使用 Redis 中的原子计数器, INCRBY(自增)、DECRBR(自减)、INCR(加1) 和 DECR(减1) 等命令。
这些命令可以直接帮助我们处理并发控制
127.0.0.1:6379> incr test-1
(integer) 1
127.0.0.1:6379> incr test-1
(integer) 2
127.0.0.1:6379> incr test-1
(integer) 3
分析下源码,看看这个命令是如何实现的
// https://github.com/redis/redis/blob/6.2/src/t_string.c#L617void incrCommand(client *c) {incrDecrCommand(c,1);
}void decrCommand(client *c) {incrDecrCommand(c,-1);
}void incrbyCommand(client *c) {long long incr;if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != C_OK) return;incrDecrCommand(c,incr);
}void decrbyCommand(client *c) {long long incr;if (getLongLongFromObjectOrReply(c, c->argv[2], &incr, NULL) != C_OK) return;incrDecrCommand(c,-incr);
}
可以看到 INCRBY(自增)、DECRBR(自减)、INCR(加1) 和 DECR(减1)这几个命令最终都是调用的 incrDecrCommand
// https://github.com/redis/redis/blob/6.2/src/t_string.c#L579
void incrDecrCommand(client *c, long long incr) {long long value, oldvalue;robj *o, *new;// 查找有没有对应的键值o = lookupKeyWrite(c->db,c->argv[1]);// 判断类型,如果value对象不是字符串类型,直接返回if (checkType(c,o,OBJ_STRING)) return;// 将字符串类型的value转换为longlong类型保存在value中if (getLongLongFromObjectOrReply(c,o,&value,NULL) != C_OK) return;// 备份旧的valueoldvalue = value;// 判断 incr 的值是否超过longlong类型所能表示的范围// 长度的范围,十进制 64 位有符号整数if ((incr < 0 && oldvalue < 0 && incr < (LLONG_MIN-oldvalue)) ||(incr > 0 && oldvalue > 0 && incr > (LLONG_MAX-oldvalue))) {addReplyError(c,"increment or decrement would overflow");return;}// 计算新的 value值value += incr;if (o && o->refcount == 1 && o->encoding == OBJ_ENCODING_INT &&(value < 0 || value >= OBJ_SHARED_INTEGERS) &&value >= LONG_MIN && value <= LONG_MAX){new = o;o->ptr = (void*)((long)value);} else {new = createStringObjectFromLongLongForValue(value);// 如果之前的 value 对象存在if (o) {// 重写为 new 的值 dbOverwrite(c->db,c->argv[1],new);} else {// 如果之前没有对应的 value,新设置 value 的值dbAdd(c->db,c->argv[1],new);}}// 进行通知signalModifiedKey(c,c->db,c->argv[1]);notifyKeyspaceEvent(NOTIFY_STRING,"incrby",c->argv[1],c->db->id);server.dirty++;addReply(c,shared.colon);addReply(c,new);addReply(c,shared.crlf);
}
总结
1、Redis 中的命令执行都是单线程的,所以单命令的执行都是原子性的;
2、虽然 Redis6.0 版本引入了多线程,但是仅是在接收客户端的命令和回复客户端的数据用到了多线程,实际命令的执行还是单线程在处理;
参考
【Redis核心技术与实战】
https://time.geekbang.org/column/intro/100056701
【Redis设计与实现】
https://book.douban.com/subject/25900156/
【Redis 的学习笔记】
https://github.com/boilingfrog/Go-POINT/tree/master/redis
【Redis 中的原子操作(1)-Redis 中命令的原子性】
https://boilingfrog.github.io/2022/05/27/Redis中的原子操作(1)-redis中命令的原子性/
【字符串命令的实现】
https://mcgrady-forever.github.io/2018/02/10/redis-analysis-t-string/
【Redis 多线程网络模型全面揭秘】
https://segmentfault.com/a/1190000039223696
【高性能IO模型分析-Reactor模式和Proactor模式】
https://zhuanlan.zhihu.com/p/95662364
【什么是事件驱动架构?】
https://www.redhat.com/zh/topics/integration/what-is-event-driven-architecture
【事件驱动架构】
https://help.aliyun.com/document_detail/207135.html
【Comparing Two High-Performance I/O Design Patterns】
https://www.artima.com/articles/comparing-two-high-performance-io-design-patterns
【如何深刻理解Reactor和Proactor?】
https://www.zhihu.com/question/26943938
【Go netpoller 原生网络模型之源码全面揭秘】
https://strikefreedom.top/go-netpoll-io-multiplexing-reactor
【Redis中使用Lua脚本】
https://zhuanlan.zhihu.com/p/77484377
【Lua 是怎样一门语言?】
https://www.zhihu.com/question/19841006
原文链接:
https://www.cnblogs.com/ricklz/p/16319382.html
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.exyb.cn/news/show-3827055.html
如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!
应广单片机开发调试应注意的问题
单片机开发调试应注意的问题 1、使用总线不外引的单片机 是最正统的单片机使用模式 符合小型、简单、可靠、廉价的单片机设计初衷 总线封闭的产品最可靠 2、使用单片机C语言编程 * C语言是简洁、高效、而又最贴近硬件的高级编程语言 * 90年代初单片机C语言就已成熟为专业…...

阿里云dun安装
wget "https://update3.aegis.aliyun.com/download/install/2.0/linux/AliAqsInstall_64.sh" && chmod x AliAqsInstall_64.sh && ./AliAqsInstall_64.sh ai1qyX...
OpenCV计算机视觉编程Python版
http://download.csdn.net/download/u014036026/9823217 好清晰的中文版...

深入理解vue中的slot与slot-scope
写在前面 vue中关于插槽的文档说明很短,语言又写的很凝练,再加上其和methods,data,computed等常用选项在使用频率、使用先后上的差别,这就有可能造成初次接触插槽的开发者容易产生“算了吧,回头再学&#x…...

Python学习指南(看完不迷路)
作为大数据和人工智能时代的必备语言,Python 优点颇多,它语言简洁、开发效率高、可移植性强,经过多年的生态建设,Python 有了大量的函数库,尤其在数据分析和科学计算领域。另外,函数在 Python 中是一等公民…...

SpringBoot整合MybatisPlus基本的增删改查,保姆级教程
概述 MybatisPlus是国产的第三方插件, 它封装了许多常用的CURDapi,免去了我们写mapper.xml的重复劳动,这里介绍了基本的整合SpringBoot和基础用法。 引入依赖 在项目中pom文件引入mybatisplus和mysql驱动依赖,如下图<dependency><groupId>com.baomidou</gro…...

应广单片机程序模块化的工程建立
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、应广编译源文件的规律 二、工程构建结构 三、示例 总结 前言 最近接触了应广的单片机开发环境,在官网下的手册的指导下也基本会用了。但是参考…...

杰理之wifi_camera跑sdram的启动时间【篇】
运行wifi_camera工程仅工作在sdram模式下,关闭sfc,sys_clk为320MHz,sdram_clk为192MHz,hsb_clk为160MHz,lsb_clk为53.3MHz...

DOM-创建元素的三种方式
<button>点击</button> <p>abc</p> <div class"a"></div> <div class"b"></div> <script> //1、document.write() 创建元素 如果页面文档流加载完毕,再调用这句话会导致页面重绘 // do…...

Leecode 106. 从中序与后序遍历序列构造二叉树 递归
原题链接:Leecode 106. 从中序与后序遍历序列构造二叉树 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(…...

java毕业设计餐厅线上点菜系统Mybatis+系统+数据库+调试部署
java毕业设计餐厅线上点菜系统Mybatis系统数据库调试部署 java毕业设计餐厅线上点菜系统Mybatis系统数据库调试部署本源码技术栈: 项目架构:B/S架构 开发语言:Java语言 开发软件:idea eclipse 前端技术:Layui、HTM…...

armv8/armv9同步异常的介绍
快速链接: . 👉👉👉 个人博客笔记导读目录(全部) 👈👈👈 1、同步异常和异步异常的概念 具备以下3个行为的称之为同步异常: • The exception is generated as a result of direct execution o…...

Web服务器,Web容器和应用服务器的区别
转载自http://www.2cto.com/os/201504/395183.html 1、什么是服务器? 2、Web服务器,Web容器和应用服务器的区别?3、Apache和Tomcat的区别?4、都是服务器,那么我们经常还听到Nginx这样的服务器,和Apache的区…...

JAVA实现视频加密
应用功能:将上传的mp4视频进行加密,用户观看视频时必须请求服务端秘钥方能播放。 前期准备: 1.java开发环境。 2.ffmepg工具。下载地址 3.秘钥文件。新建一个TXT文件,输入几个字符串,后缀名改成.key即可。 原理介绍ÿ…...

RStudio主题
获取更多R语言和生信知识,请欢迎关注公众号:医学和生信笔记 医学和生信笔记 公众号主要分享:1.医学小知识、肛肠科小知识;2.R语言和Python相关的数据分析、可视化、机器学习等;3.生物信息学学习资料和自己的学习笔记&a…...

原码反码补码原理理解
原码反码补码原理理解基础知识原码定义在这里,我们模仿一下计算机对数据运算的过程!那么所有运算都是正确的吗?我们再试一组。反码定义在这里,我们模仿一下计算机对数据运算的过程!正数加负数也没问题了,那…...

使用 Swoole 加速你的 CMS 系统,并实现热更新 (基于 Laravel 框架)
主题:使用 Swoole 加速你的 CMS 系统,并实现热更新 关于 Swoole 的简介不再在此赘述,各位可以自行查看官网的文档进行详细的了解。 本文以 MyCms 为例,简要说明 Swoole 结合传统的 CMS 系统进行使用,并实现热更新。 CMS系统:MyCms (目前v3.3+以上版本重新编写了对 Swoole…...

四川计算机二级考试wps,2021年四川省计算机等级考试(一级计算机基础及WPS Office应用)经典试题及答案...
  [导读]:2021年四川省计算机等级考试(一级计算机基础及WPS Office应用)经典试题及答案,更多四川等级考试报名时间、考试时间以及考试模拟试题,请访问易考吧四川等级考试栏目2021年四川省计算机等级考试(一级计算机基础及WPS Office应用…...

【Swin Transformer原理和源码解析】Hierarchical Vision Transformer using Shifted Windows
目录前言一、动机和改进点二、整体架构:SwinTransformer三、输入设置:PatchEmbed四、4个重复的Stage:BasicLayer4.1、SwinTransformerBlock4.1.1、创建mask4.1.2、shift特征4.1.3、为shift后的特征划分窗口4.1.4、W-MSA VS SW-MSA4.2、PatchM…...

sqlite3数据库的使用及其对应的API函数接口的使用
一、sqlite3数据库的使用 在linux中,输入sqlite3 就能进入sqlite3命令行,然后通过SQL语句执行命令。 可以使用 .quit 退出 sqlite 提示符。 1.新建表格 命令:CREATE TABLE 表名 ( 字段名1 数据类型 “约…...

任务01-04
一、相对定位 二、绝对定位 1. 当div撑开图片后有空隙的时候,使用vertical-align:middle解决。 2.一般一个东西盖在别的东西上面的时候用定位。 三、固定定位 1. 层级:同时定位在一个位置上的元素,谁在文档后面的谁的层级高&…...

wincc显示系统时间_Wincc的系统时间该如何用变量显示?
如果不用wincc的时间控件,在wincc中如何生成一个时间变量,该变量可以显示系统时间(日期、小时、分、秒)?问题补充:我现在是通过IndustrialData Bridge将Winncc数据保存到SQL数据库中,那么对应每一组变量应该时间标签。…...

[附源码]计算机毕业设计学习帮扶网站设计与实现Springboot程序
项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…...

centos 安装phantomjs
环境安装:yum install bzip2 fontconfig freetype fontconfig mkfontscale -ycd /opt/pgtar -xjvf phantomjs-2.1.1-linux-x86_64.tar.bz2创建软连接ln -s /opt/pg/phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/phantomjs查看结果:配置权限:chmod 755 /opt/pg/pha…...

应广单片机 c语言,应广单片机 MINI-C编程指南.pdf
PADAUK) MINI-C应广单片机 ( 编程指南初级篇V1.11 MINI- C 语言21.1简介21.2 MINI-C 的程序结构21.3 预处理31.4 标示符31.5 数据类型31.6 常量41.7 变量41.8 表达式41.9 特殊的符号或者符号串51.10 指针 102 程序控制语句 102.1 赋值语句 102.2 if 语句 102.3 switch 语句 122…...

Mac开发工具WebStorm
webstorm mac中文版被称为最好用的Web前端开发神器。WebStorm 新版对JavaScript,TypeScript和CSS支持更好,改进了Vue.js的体验,并为Jest集成增加了新功能。 Mac开发工具WebStorm win软件,请点我...

jeecgboot接口限制每ip每分钟访问次数
代码借鉴的别人的,自己做过部分修改 1. 新建文件夹并新建文件 \jeecg-boot-base\jeecg-boot-base-core\src\main\java\org\jeecg\common\accesslimit\ RequestLimit.java package org.jeecg.common.accesslimit;import org.springframework.core.Ordered; import…...

《Python深度学习》第五章-3(预训练)读书笔记
5.3 使用预训练的卷积神经网络 预训练网络(pretrained network): 是一个之前已在大型数据集(通常是大规模图像分类任务)上训练好、保存好的网络\color{red}训练好、保存好的网络训练好、保存好的网络。预训练网络学…...

奋斗了无数个996,我却连首付都凑不齐
近日由于阿里巴巴创始人马云对于“996”(朝九晚九一周工作六天的工作制)发表的言论在网上掀起轩然大波,关于996的讨论几乎席卷全网,微博中也已开展【你认可996工作制吗】的投票活动,正在一二线城市打拼的职场人士忍不住…...

【Python】数据分析基础:pandas
💭 写在前面:没什么好写的,不如直接开始。 0x00 pandas 介绍 ❓ Pandas 是什么? 熊猫?14年网龄的我,早就在互联网发表情包了,这种熊猫表情包我可太熟悉了。 但是我们今天要说的是 Python 里的…...

Module build failed: Error: Cannot find module ‘模块名‘
它的意思时找不到这个模块,使用npm安装这个模块就行 npm install 模块名然后发现就可以了。...

【Spring Cloud】spring cloud 调用feign请求超时 feign.RetryableException: Read timed out executing POST
本文目录 一、问题描述 二、问题原因 三、解决方案 一、问题描述 Spring Cloud项目,两个微服务之间调用报错超时,控制台抛出异常,截取部分报错: feign.RetryableException: Read timed out executing POST http://back-contr…...

社群裂变引流+亲情充值+会员自动裂变,商家5天收款279万!
各大商家其实在春节期间,营销意识很薄弱,认为很多人都忙着走亲访友,拜年,很少会出来逛街,其实呢?并不是这样! 从市场营销的角度来分析,交易量购买人数购买意愿购买能力 所以春节是…...

python实现一个web服务器
一,使用python开启一个web服务器 自带的simple_server模块开启一个服务器; from wsgiref.simple_server import make_server #导入simple_server模块#定义一个application,遵循wsgi协议; def app(env, start_response): #服务器…...

PMS150C应广单片机开发案例
PMS150C应广单片机开发案例 应广单片机价格美丽,性价比高,mini-c好用,适用于消费电子开发。但是案例demo太少了,为了方便大家能够快速入门。这里贴出了一份经典PMS150C的点灯程序代码。不是Hello world!那种,是偏向于实…...

web前端期末大作业——基于HTML+CSS+JavaScript蓝色的远程监控设备系统后台管理界面模板
🎉精彩专栏推荐 💭文末获取联系 ✍️ 作者简介: 一个热爱把逻辑思维转变为代码的技术博主 💂 作者主页: 【主页——🚀获取更多优质源码】 🎓 web前端期末大作业: 【📚毕设项目精品实战案例 (10…...

智能语音识别系统
广告关闭 腾讯云双11爆品提前享,精选热门产品助力上云,云服务器首年88元起,买的越多返的越多,最高满返5000元! 使用腾讯云语音识别完成电话录音质检 效率提升 倍 成本降低 过去 个人的工作量现在只需 个人工 台机器 同…...

java.lang.NoSuchMethodError: org.xx.AbstractHandlerMapping.obtainApplicationContext()
一、概述 中午不睡觉,来记录点东西。 某历史遗留项目,因为这几天的log4j漏洞问题要升级,但是由于种种原因,当时上线部署的包跟现在的代码已经对应不上了,现在已掌握的代码已经更新了很多内容了,当时部署在…...

CentOS7安装MySQL5.7.37
CentOS7安装MySQL5.3.37下载MySQL安装压缩包MySQL安装阶段下载MySQL安装压缩包 首先需要准备一个MySQL安装文件的压缩包“mysql-5.7.37-1.el7.x86_64.rpm-bundle.tar”,进入官网点击download 点击MySQL社区版本下载(英文) 点击download arch…...

利用TCP网络编程实现客户端和服务端简单交互
概述 在TCP通信协议下,能实现两台计算机之间的数据交互,并且它们要严格区分客户端(Client)与服务端(Server) java.net.Socket 类表示客户端java.net.ServerSocket 类表示服务端 步骤 客户端和服务端通信…...

应广单片机可以用c语言,应广单片机(一)
/****************************************************************函数名称:void Set_User_T16(void)函数功能:定时器计数定时256us函数参数:无函数返回值:无函数说明:******************************************…...

Qt开发之串口通信(三)
VSQt中获取串口COM的两种方式: 1、使用QT自带的类 bool QBatteryTesting::serialport_init() { //获得所有可用端口列表 QList<QSerialPortInfo> serialPortInfoList QSerialPortInfo::availablePorts(); if (serialPortInfoList.isEmpty()) …...

常见WEB服务器种类
IIS(Internet信息服务)英文InternetInformationServer的缩写。它是微软公司主推的服务器。IIS的特点具有:安全性,强大,灵活。 2.Tomcat Tomcat是Apache软件基金会(ApacheSoftwareFoundation)的…...

WEB服务器与应用服务器的区别
一,简述 WEB服务器与应用服务器的区别: 1.WEB服务器: 理解WEB服务器,首先你要理解什么是WEB?WEB你可以简单理解为你所看到的HTML页面就是WEB的数据元素,处理这些数据元素的应用软件就叫WEB服务器,如IIS、apache。 WEB服务器与客户端打交道,它要处理的…...

应广单片机adc_应广单片机adc和pwm例程
应广单片机Otp单核系列主要有以下几个系列,15x系列为纯iO,13x系列为带12bit的adc,17x系列为带8bit的adc,现在我用pms132B写个adc/pwm例程,方便大家快速上手.不多说,上代码.#include "extern.h"/**********adc*****************/Word usAdcSum;Word usAdcSumBak;BI…...

应广单片机开发案例
特性 l 全自我知识产权 8 位指令集 l 8 层 10bit 硬件堆栈 l 1Kx14b 程序 FLASH 存储空间(16bytes/page) l 256x8b 数据 EEPROM(16bytes/page) l 数据 EEPROM 可在应用编程 l 64x8b SRAM l 1 x 带 8 位预分频的定时器 0 l…...

C语言练习 day1
注:C语言练习100天这个专栏 摘抄自菜鸟教程。我写在这里印象更深,练习自用的。有些地方会加入一些自己的思考。 题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少? 自己先想想~…...

[深度长文] 996的经济学
全文约13000字。文章较长,建议先收藏再阅读。目录一、996的概念定义二、李嘉图的比较优势原理三、支付加班费的996是个伪命题四、996的合理化五、收入的三个来源六、一切租皆来源于权力七、快速致富的唯一途径八、一个三层架构的简明政治经济学框架九、三层架构的两…...

算法day38|509,70,746
动态规划 DP数组以及下标的含义递推公式初始化遍历顺序打印DP数组五部曲509. 斐波那契数 class Solution:def fib(self, n: int) -> int:#确定数组和下标的含义,运用一维数组if n 0:return 0elif n 1:return 1dp [0]*(n1)#初始化dp[0] 0dp[1] 1#遍历顺序,…...

倒计时 css,css实现倒计时效果
一、实现效果截图(学习视频推荐:css视频教程)二、实现原理看到上图效果应该很容易猜到原理,纯CSS的话使用轮播。通过改变图片的margin-top,再加上亿点点动画,亿点点数字图片,就实现了。使用PS建数字图片:然…...

应广单片机PFC154
前面我们讲了PFC151,今天我们来讲一下PFC系列另外一个型号,PFC154。我们还是通过具体数据来直观的了解这款芯片。 系统特性 1.高抗干扰(High EFT)系列 2.特别适用于AC电源供电的、阻容降压电路的、需要较强抗干扰能力的&#x…...

Java开发童年小游戏
黄金矿工、贪吃蛇、飞机大战……这些名字你是否还记得? 这些陪伴我们成长的小游戏现在已然被手游取代,但它们带给我们的美好记忆却从不曾消失。 今天带来两小时就能自己动手开发这些小游戏的教程,希望大家能在这个纷扰的时代,通…...

ZooKeeper的监听原理
Main线程创建listener线程和connet线程 ,监听事件发给connet线程,数据有变化Zookeeper通知到listener线程...

HTML+CSS制作简单的家乡网页 ——我的家乡介绍广东 web前端期末大作业
家乡旅游景点网页作业制作 网页代码运用了DIV盒子的使用方法,如盒子的嵌套、浮动、margin、border、background等属性的使用,外部大盒子设定居中,内部左中右布局,下方横向浮动排列,大学学习的前端知识点和布局方式都有…...

作图从此不求人,代谢组学宝藏作图能力提升班你来不来?
俗话说,一图胜千言。 在运用代谢组学研究课题的过程中,数据的分析并将其可视化表达是需要掌握的重点技能。 质量上乘的SCI的图片表格是论文的加分项,能极大提高论文的质量。很多同学文章写得多,勤勤恳恳投杂志、SCI,…...

【Java面向对象】04 对象构造
对象构造 1.默认值 数值0布尔false引用类型null 2.无参构造 如果类中没有提供任何构造函数,那么会默认添加一个无参构造如果提供了构造器,那么不再提供无参构造 3.显示域初始化 private String name "";// 属于类,所有构造出…...

golang(gin框架),基于RESTFUL的跨语言远程通信尝试
golang(gin框架),基于RESTFUL的跨语言远程通信尝试 背景:在今年的项目实训过程中,遇到了这样的问题: 企业老师讲课实用的技术栈是Java springboot。 实训实际给我们讲课以外的开发时间非常短暂,为了方便协作、提高效率,我们想要将系统模块拆分成几个粒度比较大的分布式服…...

为什么要分区有必要分区吗
非常有必要。 这样可以避免经常读写硬盘的某个部位,分区后可以更加充分的利用硬盘。 你可以这样理解,你一个水杯,是300毫升的容量。而你每次只装100毫升水,这样杯子的上面200毫升的地方,永远也用不到。当然咱们存文件也…...

SWUST OJ 189: 素数判定
题目描述 给你两个数a、b,现在的问题是要判断这两个数组成的区间内共有多少个素数 输入 多组测试数据。 每个测试数据输入两个数a、b。(2<a,b<1000) 输出 输出该区间内素数的个数。 样例输入 2 4 4 6 样例输出 2 1 参考程序 #include<stdio.h> int main…...

B树的C语言实现
前言 今天我们再来学习另外一种高级数据结构B树,我们知道树的查询时间复杂度和其树的高度有直接关系,当我们向红黑树里面插入大量的数据时,有两个问题: (1)首先,内存是有限的不可能无止境的一直…...

python 报错汇总-- pip install pycrypto
python 报错汇总-- pip install pycrypto 很多新手和老鸟在安装pycrypto时候会报各种错, 废话不多说,直接上: 原因 我也报了文末的错说是VC14什么的,花了差不多三天时间才搞明白咋回事: 不维护了!!不维…...

PyCrypto安装和使用示例
有的时候,用python来解密比用C快很多,省去了很多建工程的力气。Python是每一个加密解密人员必备的一门语言 :) 下面我们来说说如何使用Pycrypto来解密加密的数据。 步骤一:安装PyCrypto,下载地址我给你准备好了:http…...

PyCrypto密码学库源码解析(二)RSA参数生成
Python Crypto库源码解析(二) RSA参数生成 * 版权声明 * 引用请注明出处,转载请联系: h0.1cfoxmail.com 本文主要讲解pycrypto库中RSA参数生成的实现方法。主要涉及的模块是PublicKey.RSA 和其继承模块PublicKey._RSA。 Python Crypto库源码…...

【Flink】检查点算法实现原理之检查点分界线
一 检查点的实现算法 一种简单的想法(同步的思想) 暂停应用保存状态到检查点再重新恢复应用(Spark Streaming) Flink 的改进实现(异步的思想) 基于 Chandy-Lamport 算法的分布式快照算法将检查点的保存和数…...

中国十大网络安全公司
1、深信服科技股份有限公司 2、奇安信科技集团股份有限公司 3、启明星辰信息技术集团股份有限公司 4、天融信科技集团股份邮箱公司 5、美亚柏科信息股份有限公司 6、蓝盾股份有限公司 7、绿盟科技集团股份有限公司 8、任子行网络技术股份有限公司 9、杭州安恒信息技术股份有限公…...

中国SD-WAN企业排名
全球及中国SD-WAN主要企业包括: Versa Networks, Cisco Meraki、VeloCloud、Riverbed、CloudGenix、Talari、Viptela、Peplink、CloudGenix、Nokia Nuage、Citrix、Silver Peak、Fatpipe、Riverbed、Cradlepoint、Aryaka、Nuage Networks。 中国SD-WAN解决方案&am…...

Vue项目devServer.proxy代理配置详解
Vue项目devServer.proxy代理配置详解目录概述需求:设计思路实现思路分析1..config.js文件中,引入依赖项2.devServer.proxy 可以是一个指向开发环境 API 服务器的字符串3.更多控制行为参考资料和推荐阅读Survive by day and develop by night. talk for i…...

世界500强和中国500强企业名单(2004年度前100名)
排名公司名称中文名称总部所在地主要业务营业收入百万美元1Wal-Mart Stores沃尔玛美国一般商品零售 263009.02BP英国石油英国炼油 232571.03Exxon Mobil埃克森美孚美国炼油 222883.04Royal Dutch/Shell Group壳牌石油英国/荷兰炼油 201728.05General Motors通用汽车美国汽车与零…...

[油猴脚本开发指南]脚本自动化之模拟点击和表单填写
转载自油猴中文网:bbs.tampermonkey.net.cn 李恒道QQ4548212 油猴中文网bbs.tampermonkey.net.cn TamperMonkey GreaseMonkey 油猴脚本 脚本交流 脚本分享 油猴脚本开发 油猴基础开发 油猴 油猴中文 公众号:叛逆青年旅舍 https://bbs.tampermonkey.net.cn/ 本节主…...

js实现点击按钮出现输入框本地修改文字内容功能
想要实现像网盘一样,点击重命名按钮,将文件的文件名,变成一个输入框,可以在里面修改文件名。 目前是对一个按钮进行操作,如果是多个,还要进行修改。欢迎讨论,提供更好的方法。 <html><…...
谷歌浏览器扩展程序-实现按钮自动连续点击
谷歌的扩展程序非常简单。必要的文件只有manifest.json文件。在该文件中声明了扩展的名称、版本、权限、设置选项和其他的一些和扩展相关的元数据。 我所做的扩展实现的主要功能是按钮自动连续点击。该扩展最初的想法来自于英雄联盟一个领取头像的活动,该活动要求玩…...

怎么把dns服务器改成自动,怎么把dns改成自动获取
1.每次开机电脑都默认是手动设置DNS,怎么改成默认自动获取按如下方法设置电脑自动获取DNS:1、将鼠标光标移到任务栏开始图标处,左键单击开始图标;2、在弹出的启动菜单中选择左侧的“控制面板”左键单击选择;3、在控制面板界面选择“网络和共享…...

如何编写自动点击按钮
(1)首先要有一个点击div,里面有一个click动作按钮,且改动作按钮对应一个点击之后要做的事情。这里是跳转到一个外部链接, click"jump()" (2)然后要自己自定义的指令,这个…...

腾讯云服务器的规格机型信息分析
腾讯云CVM云服务器有多种实例类型规格,不同规格适用于不同的使用场景,CVM实例规格是由CPU、内存、存储和网络等组合而成。腾讯云百科分享CVM云服务器规格族大全、实例特点及适用场景等: 腾讯云CVM云服务器规格大全 更多参阅官方文档 腾讯云CV…...

媒体访谈| 知道创宇邓金城: DDoS攻势愈烈,抗D服务需不断优化
近日,网安产业资讯媒体安全419开展《在线业务抗D解决方案》系列调研,知道创宇作为业内具备专业抗D能力的安全厂商参与调研。知道创宇产品技术中心副总经理邓金城在访谈中分享了知道创宇在抗D领域的前沿趋势、创新技术及实践案例。以下内容引用自安全419。…...

超算优化重在存储,DAOS助力瑞金打造先进的生信大数据平台
文章来源:头部科技【导读】「为什么说DAOS是为高算力匹配的高性能存储?」高性能计算(High performance computing,缩写HPC)又名超算,即以超强算力解决数据密集型的各类科学问题。早期的HPC主要用于解决国家…...

阿里云新增三大高性能计算解决方案,助力生命科学行业快速发展
图:阿里云高性能计算研发负责人何万青 8 月 5 日,在 2022 阿里云生命科学与智能计算峰会上,阿里云高性能计算研发负责人何万青发布了《生命科学行业云上解决方案及最佳实践》白皮书,同时推出高性能容器、大内存、高 IO 等三大高性…...

[附源码]计算机毕业设计springboot校友社交系统
项目运行 环境配置: Jdk1.8 Tomcat7.0 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: SSM mybatis Maven Vue 等等组成,B/S模式 M…...

Intel至强Phi 5110P集群跻身绿色500强名单
芯片制造商英特尔的至强Phi加速的灯塔集群(Beacon cluster)登上了绿色500强名单的头把交椅。AMD和Nvidia庆祝了它们位列公知的基于Linpack性能的高性能计算集群前500强的位置,英特尔同样打入了很多人声称的重要胜利。Appro由至强Phi 5110P加速卡支撑的Beacon集群登顶…...

解读英特尔高性能基因
如何在高性能计算领域获得成功?答案绝非商业准则或秘籍,更不是言之凿凿的成功指南。在这个看似封闭、但又充满无限变化和机遇的地带,那些成功者在特定时刻所遭逢的机遇、在特定问题面前的抉择,也无可模仿,否则大有可能…...

突破数据分析瓶颈,寻因生物单细胞测序数据分析迈入云时代
世上没有两片完全相同的树叶,人体内的每两个细胞也是截然不同的。长久以来,基因检测技术主要是在组织层面对样本进行解析,获得的是成千上万个细胞的平均值,但这会让很多信息是被隐匿,对疾病的认知和理解存在很大的障碍…...

华大基因茅矛:云计算让精准医疗走进生活
2016年是“十三五”的开局之年,也是中国医疗卫生行业的关键一年。现在看来,也会是医疗行业和以大数据为代表的信息技术相互融合发展之年。今年4月,国务院办公厅印发《深化医药卫生体制改革2016年重点工作任务》,其中不仅谈到了要加…...

大数据解码人类基因,精准医疗不再遥远!
很多人都思考过这样一个问题:假如生命只剩下三天,应该怎样去过? 从生命价值角度考虑,这只是一种“假设”;但从生命本身来看,我们之所以这样假设,是因为人类对自己的生命充满了未知,谁都无法预测…...

基于炼丹神器深度学习下的生命科学冷冻电镜单细胞基因分析的解决方案
生命科学 | 冷冻电镜 | 蛋白质结构 深度学习 | 基因测序 | 卷积神经网络 当前随着冷冻电镜、蛋白质组学、深度学习、基因测序、卷积神经网络、高性能计算、单细胞基因、数据挖掘、数据分析、靶点发现、晶体预测、AlphaFold等技术的快速发展,生命科学开始被逐渐被人…...

重塑数据中心:英特尔® 至强® 处理器可扩展家族
我们的时代正在发生翻天覆地的变化。数字体验已经渗透到我们生活的方方面面,企业使用技术获取市场竞争优势的能力正日渐成为决定其成败的关键。越来越多的终端设备和更为丰富的数据流推动了数据的爆炸式增长,而数据爆炸也正成为这场转型的重要推动力。作…...

TBtools | 多图合一至强版教程!进化树 + Motifs + 结构域 + 启动子 + 基因结构 + ....
放一张效果图,这些,三四年前的东西,我其实一直懒得说。 写在前面 “Gene Structure View (Advanced)”这个功能可以说,也是一时兴起写出来的。开发的主要动机,还是发现师弟师妹在做的事情实在是太费时间精力。就这样…...

ios连不上微软游戏服务器,iOS 设备上已经支持微软的 Xbox 云游戏服务
继 4 月中旬开始的仅限邀请的 Beta 测试之后,微软已向iOS 和 PC 上的所有Game Pass Ultimate订阅者推出其 Xbox 云游戏服务。随着今天的公测开始,您可以访问xCloud 网站并通过浏览器开始玩游戏通行证库中包含的一些游戏。在 PC 上,该服务支持…...

Unity 调用IOS ATT授权弹窗(AppTrackingTransparency)
前提 ios升级到14.5版本之后,强制要求app授权AppTrackingTransparency。不然审核不通过。经过研究,成功接入了ATT弹窗,下面把接入步骤分享给大家。 调用步骤 创建一个.mm文件,里面写ios代码,然后放到unity工程的Plu…...

网络编程知识总结 之 iOS网络框架概述
本文主就iOS开发所使用的网络框架进行概述,对Objective-C中网络层的组织形式进行简要的分析 iOS网络框架 每个iOS应用的网络层都是基于Apple提供的网络框架来实现的,该网络框架的构成如下图所示 其总共包括四层:Cocoa层(基于Obje…...

信息学奥赛一本通——1899:【17NOIP提高组】小凯的疑惑
文章目录1899:【17NOIP提高组】小凯的疑惑【题目描述】【输入】【输出】【输入样例】【输出样例】【提示】【样例说明】【数据范围】代码1899:【17NOIP提高组】小凯的疑惑 时间限制: 1000 ms 内存限制: 262144 KB 提交数: 1930 通过数: 1118 【题目描述…...

ios 搭建虚拟服务器,iOS开发网络篇—搭建本地服务器(示例代码)
一、简单说明说明:提前下载好相关软件,且安装目录最好安装在全英文路径下。如果路径有中文名,那么可能会出现一些莫名其妙的问题。提示:提前准备好的软件apache-tomcat-6.0.41.tareclipse-jee-kepler-SR2-macosx-cocoa-x86_64.tar…...

ios运行html游戏,Html游戏 - IOS的Safari浏览器崩溃
我正在运行一个HTML应用程序开发使用打字稿,pixi.js webgl,网络音频。Html游戏 - IOS的Safari浏览器崩溃游戏在各种设备和浏览器上的windows和android上运行良好。然而,在ios safari上,我们会在所有设备上(包括iphone 4/5/6&a…...
前端开发和后端开发哪个难学
相对来讲,后端开发可能更难学一点。 前端对于逻辑思维的要求不是那么高,学起来不是很难。很多前端开发人员都是从零基础开始学的。后端开发需要程序员有很好的逻辑思维,学习的知识也不少,学习起来可能并没有那么简单。前端开发和…...

一文说明前端和后端的区别、职业发展以及就业前景!
前端和后端要做什么?前端开发和后端开发是软件开发的重要组成部分。前端开发主要做的是用户所能看到的前端展示界面;后端开发主要做的是逻辑功能等模块。要问哪个辛苦加班多?其实都差不多,毕竟技术研发行业都不会太轻松。下面&…...

php和前端哪个更有发展前景,前端的前景如何?是不是比后端研发前景差?
一个好的前端工程是基本上就是一个全栈工程师了。一般后台用 PHP 那么前端工程师也是有能力搭建整个网站的。自从node.js和mongodb出现之后,那么只会js的前端工程师也可以独立完成从前端到后台数据库所以的代码。这就是优势,在软件工程里人与人之间的交流…...

前端和后端哪个工资高?做前端好还是做后端好?
前端和后端哪个工资高?事实上,两个都是属于技术研发岗位,都是高薪有前途的职业,不存在说哪个工资更高些,都基本在一万到五万之间,工资的差别主要体现在个人技术上。要问做前端好还是做后端好?其…...

mysql前端还是后端_前端和后端哪个发展好点?
前端和后端哪个工资高,哪个发展前景好?事实上,两个都是属于技术研发岗位,都是高薪有前途的职业,不存在说哪个工资更高些,都基本在一万到五万之间,工资的差别主要体现在个人技术上。要问做前端好…...
前端和后端哪个工资高?工作内容和晋升空间差别大吗?
前端和后端哪个工资高?工作内容和晋升空间大吗? 事实上,两个都是属于技术研发岗位,都是高薪有前途的职业,不存在说哪个工资更高些,都基本在一万到五万之间,工资的差别主要体现在个人技术上。要问做前端好还是做后端…...

1546_AURIX_TC275_CPU子系统_指令耗时以及程序存储接口
全部学习汇总: GreyZhang/g_TC275: happy hacking for TC275! (github.com) 这里接触到了几种测试的方式。其中一个是反复执行同一个命令,看看执行之间的间隔。执行的时候,命令是有一定顺序的。这样,有时候流水线等特性会导致效率…...

前端和后端(Java)开发哪个难?,哪个学习容易一点?
前端和后端(Java)开发哪个难?,哪个学习容易一点? 关于前端和后端java学习难以程度,以下是我的分享。 难易程度: web前端开发 起点低。容易入门,相对于Java来说,前端对…...

一分钟整明白web前端和Java后端的就业前景
前端:前端即网站前台部分,运行在PC端,移动端等浏览器上展现给用户浏览的网页。随着互联网技术的发展,HTML5,CSS3,前端框架的应用,跨平台响应式网页设计能够适应各种屏幕分辨率,完美的…...

了解一下:前端和后端哪个工资高?做前端好还是做后端好?
前端和后端哪个工资高?事实上,两个都是属于技术研发岗位,都是高薪有前途的职业,不存在说哪个工资更高些,都基本在一万到五万之间,工资的差别主要体现在个人技术上。要问做前端好还是做后端好?其…...

相对于就业来讲,前端工程师和后端开发哪个比较好?
在开始这个问题前,先说一下前端和后端两者之间都是干什么的?有哪些区别?通俗地讲,前端干的工作是用户可以直接看得见的,而后端开发的工作主要在服务端,用户不太能直接看到。虽然前端开发和后端开发的工作有…...

前端和后端到底有什么区别?待遇和前景如何?
很多人问我前端与后端的区别,还有前端与后端的就业前景哪个好!今天小编就来详细和你们说一下它们的区别!(文章转载自乐字节) 目录: 一、什么是前端、什么是后端? 二、、前端、后端需要掌握哪些技…...

解决不能打开网站但能ping通
windowsR组合键打开运行框,输入“cmd”打开dos窗口 输入“netsh winsock reset”回车然后重启电脑即可...

vue启动项目时自动打开网站
只要在项目的config/index.js中吧 autoOpenBrowser改为true便可以...

为什么edge浏览器无法用IE打开网站?
需要在edge右上角的“..."中下面的”设置“->”默认浏览器“->”让Internet Explorer 在 Microsoft Edge中打开网站“ 设置为 ”从不“; 关闭 ”允许在Internel Explorer模式下重新加载网站“; 这种设置下,在edge中用IE打开网站…...

vbs打开网站网址
Set objeShell CreateObject("Wscript.Shell") objeShell.Run("http://www.baidu.com")...

iapp使用QQ内置浏览器打开网站代码
iapp使用QQ内置浏览器打开网站代码! *注意:*网站地址只允许是腾讯的网站地址! iapp代码如下: s wzdz"腾讯网页链接" java(bytes,wzdz,"String.getBytes","String","utf-8") java(bytes…...

chrome怎么打开网站会自动下载|chr…
转载地址:http://www.betterhelper.net/bencandy.php?fid38&id3499 前面我们已经介绍了关于chrome打开网站会自动下载的解决办法、chrome经常提示此类文件会损坏计算机的解决办法、chrome弹出下载提示的解决办法, 遇到相同问题,但是还没…...
Chrome浏览器地址栏https显示红叉和删除线,无法打开网站,且没有继续选项
使用chrome浏览器打开带https开头的网址时,有时无法打开。 这是因为有的https没有经过验证,证书过期或者根本没有证书,浏览器为了安全起见进行了提示,一般情况下点击 “高级” 选项便可以 “继续” 浏览,有时不会出现 …...
求助打开网站显示welcome to nginx!
哪个大师能帮我看一下这个要怎么弄呢。...

Compose 动画艺术探索之动画规格
本篇文章是此专栏的第四篇文章,如果想阅读前三篇文章的话请点击下方链接: Compose 动画艺术探索之瞅下 Compose 的动画Compose 动画艺术探索之可见性动画Compose 动画艺术探索之属性动画 动画规格在上一篇文章中提到过,不过上一篇文章中说的…...
计算机网络体系结构与打开一个网站的全过程
1. 计算机网络体系结构 每一层的作用如下: 应用层:允许访问OSI环境的手段(应用协议数据单元APDU) 表示层:对数据进行翻译、加密和压缩(表示协议数据单元PPDU) 会话层:建立、管理和…...
打开网站执行了那些操作
打开网站执行了那些操作 《小李的别虐日常》 今天李四觉得闲来无事,正好看见了老王在试穿张三给他的新帽子,李四信心满满想要在老王面前装个B,来反正你也是闲来无事,你来考考我;老王说:你个憨憨,…...

python冒号排序教程
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。…...

java 冒号转义,如何在属性文件中转义冒号(:)?
I am using a properties file to store my applications configuration values.In one of the instances, I have to store a value asxxx:yyy:zzz. When I do that, the colon is escaped with a back slash\ resulting in the value showing as xxx\:yyy\:zzz in the prope...

java 切割冒号_java split 冒号(java中split是什么意思啊)
:切分字符串为数组,String value "register.xml" String[] values value.split(".")最佳案String s "123-456-789-0123"; String arr[] s.split("-")&…...

visual studio C++冒号:与双冒号::的使用说明
1. 冒号 (1)表示机构内位域的定义(即该变量占几个bit空间) typedef struct _XXX{unsigned char a:4;unsigned char c; } ; XXX(2)构造函数后面的冒号起分割作用,是类给成员变量赋值的方法&…...

电脑怎么打出冒号符号_冒号的用法有哪些?写作文的时候冒号怎么用?冒号在电脑上怎么打出来?...
我们在写作文的时候,做阅读题的时候经常会用到或见到冒号,各种标点符号都是有自己的使用方法,那么今天小编来告诉大家冒号的用法有哪些,小编会整理示例来让大家学习,同学们仔细看了哦!文尾小编会告诉大家在电脑上冒号怎…...
我在滴滴数据分析岗实习8个月的收获(文末附内推机会)
作者:海潮来源:数据管道大家好,我是宝器!今天分享一下交流群里海潮兄弟的「数据分析岗」求职与工作经验,以下是海潮兄弟的自诉,全文共4825字,6图,阅读大概需要15分钟。作者介绍&…...

会议及作用篇--项目管理(十八)
补充: 头脑风暴(来自MBA智库百科) 头脑风暴法(Brain Storming,BS法)又称智力激励法、或自由思考法(畅谈法,畅谈会,集思法) 头脑风暴法简介 头脑风暴法出自“头脑风暴”一词。所谓头脑风暴(Brain-…...
在滴滴数据分析岗实习的8个月
今天分享一下海潮兄弟的「数据分析岗」求职与工作经验,以下是海潮兄弟的自述,全文共4825字,6图,阅读大概需要15分钟。作者介绍:双非院校刚毕业的统计硕士,目前在滴滴工作,有8个月的数据分析实习…...

复盘2020年丨在线教育最常用的转化方法(下)
良心整理分享!!全文共11274字,分为上下两个篇内容,全文阅读时间预计12分钟,看不完记得点赞收藏(此篇为下文)上篇我们讲解了训练营开始前的准备工作和流程详情那接下来要分享的是训练营从开始到结…...

MVCC 时光机:在 TiDB 的时空自由穿梭丨渡渡鸟复兴会赛队访谈
TiDB 处理各种灾难故障可谓轻车熟路,但是常言道“天灾易躲,人祸难防”,对于各种误操作、bug 写入错误数据、甚至删库跑路,目前还没什么招。我们项目最初也是为了处理这些“意料之外”的事故。项目最初的名字叫 TiDB Flashback&…...
辞职了要不要退微信群,如果要,如何“优雅地退群”?
天下没有不散的筵席,辞职在职场中很常见,辞职了要跟公司跟同事散开了,那之前加入的各种公司微信群还有必要留着吗?大部分人觉得要退,主动退才是明智的选择,但是如何“优雅地退微信群”也是讲究方式的 天下…...
微服务架构在二手交易平台(转转)中的实践
本文根据ArchSummit北京2016大会分享整理下面由我跟大家分享微服务架构在二手交易平台(转转)中的实践。大家知道微服务架构现在是非常火热的一个话题,具体在交易平台里面它是怎么应用实践的,接下来的45分钟我会和大家深入的探讨一…...

诗词温习集:跟梁瀚文一起重温诗词(唐诗)之《登鹳雀楼》
诗词温习集:跟梁瀚文一起重温诗词(唐诗)之《登鹳雀楼》《登鹳雀楼》 唐.王之涣 白日依山尽,黄河入海流。 欲穷千里目,更上一层楼。 译文 注释 1.鹳雀楼:旧址在山西永济县,楼高三层&…...

什么是方法?
何谓方法 System.out.println(),那么它是什么呢? System是一个类,out是对象,println()是方法。意思是调用系统类里面的标准输出对象out中的方法println()方法。Java方法是语句的集合,它们在一起执行一个功能。 方法是…...

社畜什么意思,如何理解我是社畜,社畜青年是什么意思一起来看看
最近大家可能会看到很多网友自称自己是社畜青年,那么究竟这里的社畜青年是什么意思,社畜代表什么含义,今天我们就一起来具体了解一下。 首先大家要明白社畜这个网络语,最早是从日本传过来的,在日本一个形容上班族的贬义…...

飞入菜花无处寻的上一句是什么,飞入菜花无处寻是什么意思
“__________,飞入菜花无处寻”,你知道空白处该怎么填写吗?飞入菜花无处寻的上一句是什么,你知道吗?飞入菜花无处寻是什么意思呢?我们一起来学习下吧。 飞入菜花无处寻的上一句 “儿童急走追黄蝶,飞入菜花无处寻。” 所以飞入菜…...

c语言split函数是什么,R语言strsplit函数用法深入详解
1、R语言strsplit用于分割字符串创建测试数据> test > test[1] "aa bb cc dd ee ff"> class(test) ## 测试数据为字符[1] "character"2、按照指定分隔符拆分字符串> a > a[[1]][1] "aa" "bb" "cc" "dd&…...

java中的遍历是什么_Java中遍历List集合三种方法总结
package com.list.Test;import java.util.ArrayList;import java.util.HashMap;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Map.Entry;/***author 791202.com*/SuppressWarnings("unused")public class MapTest {priv...
开学啦!班主任约你一起诗与远方......
你流下的每一滴汗水,终将成为浇灌未来的雨露。 一副行囊,一腔勇气,你们踏浪而来,与你们相遇,我们已期盼已久。 去年九月,你们作为大一的新生,积攒了一个春天的力量,在那个炎夏&…...
三分钟带你看懂金鹏奖最佳短片《盒子》,跟随你的内心或许才能到达诗和远方!...
本文将给你推荐一个金鹏奖最佳短片《盒子》,该影片视觉效果富有创意,兼顾技术性和艺术性。故事虽短却简洁有力,主题也极具思想!片名:盒子来源地:斯洛文尼亚短片类型:动画导演:杜桑卡…...

天涯若比邻的上一句是什么,这首诗作者是谁、表达的是什么意思?
“__________,天涯若比邻。” 这道语文试题你会吗?天涯若比邻的上一句是什么,你知道吗?你还记得天涯若比邻这首诗的作者是谁吗,天涯若比邻表达的是什么意思呢?我们一起来了解下吧。 天涯若比邻的上一句 海内存知己,天涯若比邻。…...

挥一挥衣袖,贝索斯宣布“退位”,去追寻“诗和远方”
“每一天都是第一天” ——贝索斯 带领着亚马逊在疫情期间连连创造股价奇迹的贝索斯,突然决定功成身退。 美国时间2月2日(周二)美股盘后,亚马逊在四季度财报会上宣布,杰夫贝索斯(Jeff Bezos)将辞…...

贝索斯宣布“退位”,去追寻“诗和远方”
本文转载自 硅星人 “每一天都是第一天” ——贝索斯 带领着亚马逊在疫情期间连连创造股价奇迹的贝索斯,突然决定功成身退。 美国时间2月2日(周二)美股盘后,亚马逊在四季度财报会上宣布,杰夫贝索斯(Jeff Be…...
区块链的诗与远方
作者:徐川 本文系作者为 BCCon 大会迷你书《区块链生态技术谈》所作的卷首语。 “这个世界不只有眼前的苟且,还有诗与远方。” 现在已经没人会去关心中本聪是在一个什么样的情况下发布比特币了吧,然而,我还是想跟你再谈一谈。 时间…...

父母尚在苟且,你却在炫耀诗和远方
http://www.baidu.com/link?urlIsILZWhvxx6fmMbU7jtEIDipmHZp_7Tvt6hsvmlePt6R2ep8zwEv7ACs4dvmoa8SrkBDS-EfbGneKWdjhPTwqWPCAkX3MQcfj8Jax3fS6fm&wd&eqidb24eb5670009d94e0000000356ee090f 随着国庆长假的结束,一年几度的朋友圈杯摄影大赛也暂时告一段落…...

天下武功为快不破,戏说Python与Go高并发争锋!
在这个以斗气大陆横行的世界,每一个大的势力宗门都有自己的杀手锏的功法,比如老牌的古族有C这样的巨无霸语言,药族有C语言,几乎斗气大陆所有的操作系统都是用C语言做的,毕竟斗气都要靠吃丹药维持。而实力非常猛的魂族有…...

将进酒、凉州词(两个版本)、 回乡偶书
这些诗词,真的特美。 现在有很多,以诗词为歌词,配曲子来唱的,感觉太棒了。据说古代,就这样玩的。 流传千年的歌词(诗),会有多牛。 不是现在那些流行歌词能比的。 我大中华的文化…...
python儿童编程例子代码-少儿编程之 Python
一个孩子爸爸联系我,想咨询如果让娃学习Python。我思考了好久,两个问题一直困扰着我: 1. Why Python?图片发自简书App 这是我在网上找到的Python具体应用的领域,大人学习可以从自己的行业入手,那么如何让小孩子入门呢…...

带有风的诗词_含有风的诗句_诗词完美版
《含有风的诗句》含有风的诗句(一):1、却余人物淘难尽,又挟风雪作远游。梁启超《太平洋遇雨》2、夜来风雨声,花落知多少。孟浩然《春晓》3、春风得意马蹄疾,一日看尽长安花。孟郊《登科后》4、随风潜入夜,润物细无声。…...

儿童背诵古诗词-3
1 春江花月夜-张若虚 春江潮水连海平,海上明月共潮生 滟滟随波千万里,何处春江无月明 江流宛转绕芳甸,月照花林皆似霰 空里流霜不觉飞,汀上白沙看不见 江天一色无纤尘,皎皎空中孤月轮 江畔何人初见月࿰…...

儿童诗词学习
鹿寨(王维) 空山不见人,但闻人语响。 返景入深林,复照青苔上。 独坐敬亭山(李白) 众鸟高飞尽,孤云独去闲。 相看两不厌,只有敬亭山。 杂诗(王维) 君自…...

关于某某大学校园网认证系统的一些工作
由于我们学校的校园网认证是弹出页面的那种,每次输密码都会很蛋疼,于是大一的时候我写过一个宏,每次打开认证界面按一下设定好的键就可以自动填上账号密码了,用了将近三年,效果一直不错。 但最近我发现了一个新的问题…...

校园网认证系统-802.1x协议介绍
本文转自http://hi.baidu.com/xinghui100/blog/item/e0edb36dbbacb8fe43169405.html802.1x协议解析 802.1X协议是由(美)电气与电子工程师协会提出,刚刚完成标准化的一个符合IEEE 802协议集的局域网接入控制协议,其全称为基于端口的访问控制协…...

重构信息茧房
我现在越来越反感弹幕的存在。其罪有二:一为扰乱我感受视频原有的内容;二为传播戾气。首罪对我危害最大,回顾以往,视频上的弹幕是如何将浮躁、快节奏、段子等互联网无聊产物潜移默化的塞入我的思维。它带给我快乐的价值远远低于收…...

Ending Prison Break(越狱)
用了三天时间看完了《Prison Break》,这是看完了《Desperate Housewives》后看的第二部美国电视剧,还算不错,虽然只有一季,但绝对能让人过把瘾了,一个和desperate housewives 完全不同风格的剧集,每一季都环环相扣&…...

图森计划裁员25%/ 特斯拉被曝将冻结招聘/ 天才黑客Geohot从推特辞职…今日更多新鲜事在此...
日报君 发自 凹非寺量子位 | 公众号 QbitAI大家好,今天是12月22日星期四,距离周末还有两天,距离圣诞还有三天。今天科技圈都有哪些大事发生,快来和日报君一起康康~图森计划裁员25%当地时间周三,图森未来宣布…...

我眼中的光明·第四周
冰冻三尺一 冰冻三尺,非一日之寒。日积月累,方能见效。见效越快意味着越不能持久。珍惜每一分钟的给予,珍惜在一起的每一刻钟。我们千万不要和自己心爱的人之间冰冻三尺。如果有了矛盾及时解决,将这一点点的矛盾之冰及时融化。因为…...

《越狱》中的项目管理 [原稿]
很早的时候写的一篇文章,那时候还只是个主管,文章发表于《商界评论》(2007第六期),转载请注明出处 五一期间,又看了一遍《越狱》的第一季。其实,越狱并非一个新鲜的题材,记得之前就有…...

iOS时间那点事
NSDate NSDate对象用来表示一个具体的时间点。NSDate是一个类簇,我们所使用的NSDate对象,都是NSDate的私有子类的实体。NSDate存储的是GMT时间,使用的时候会根据 当前应用 指定的 时区 进行时间上的增减,以供计算或显示。 可以快…...
《越狱》穿帮集锦(第一季)
第一集里面MS与哥哥在粉刷墙壁(注意、刷子是白色的)在下工返监时候交接工具,白刷子居然变成绿的了。第二集里面,MS从操场上的长椅下拆下来螺栓,计划可以磨成一把头部为正六面体的改锥。(注意、螺栓与地面的…...

饥荒 阿里云服务器搭建记录
获得一个服务器 我选的是阿里云学生免费体验的服务器 ubuntu 4核(vCPU) 8 GiB 3Mbps 带宽 饥荒 照搬的 饥荒云服务器搭建流程【Steam】【阿里云】 安装工具 sudo apt-get update #更新软件源 sudo apt-get upgrade #更新软件 sudo apt-get install dos2unix #转换格式工具…...

饥荒开服(含各种踩雷)
饥荒开服(含各种踩雷) 纯小白,用过Mac电脑.这就是我全部Linux基础了,结果搭建了一个上午才勉强搭出来过程中感觉比饥荒还饥荒.所以我在这里分享一下我自己的搭建过程…我是使用的阿里云的Ubuntu 18.04 64位的服务器,我尽量会把出错误的各种情况说清楚 0.安装步骤 安装依赖下载…...

饥荒 出现error during initialization的解决方法
最先我的电脑是可以运行饥荒的,然而,我重装系统后,打开饥荒这款游戏。游戏黑屏显示error during initialization错误。我在网上找了很多方法,花了很多时间,各种折腾。最终,完美解决了。或许,我的…...

在centos上搭建饥荒服务器
用这篇文章记录一下我搭建饥荒服务器的过程,在阅读参考本文章前,您需要: 拥有安装CentOS的云服务器,使用其他操作系统在部署饥荒服务器的时候可能会出现问题包含cluster_token的地图文件夹。这部分操作比较简单,现在在…...

饥荒服务器怎么改成无限模式,tgp饥荒服务器搭建怎么搭建无尽模式
匿名用户1级2017-03-08 回答TGP饥荒专用服务器创建地表及洞穴的方法还有很多玩家们不太熟悉,具体该如何操作?接下来为大家带来ldquo;安菲儿公主rdquo;分享的详细操作玩法,一起来看看吧。服务器搭建图文教程点击查看首先创建一个地表服务器1、…...

【MySQL】MyCAT三大配置文件详解(MySQL专栏启动)
📫作者简介:小明java问道之路,2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建工设优化。文章内容兼具广度深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公…...

【学习分享】C语言程序设计思维导图—4:基本输入输出
分享在华为云Classroom中学习C语言时做的思维导图。 在课程里,第四章为基本输入输出和顺序程序设计,在学习总结的过程中,把顺序程序设计放到了下一章节,将三种基本结构放到了一章里。下载链接:https://bbs.huaweicloud…...

CAD一个命令快速绘制箭头,真的是敲极快!
CAD中利用多段线可以快速绘制一个箭头,具体步骤如下: 执行多段线【命令PL】,按下空格 鼠标指定起点,单击一下左键,再输入命令【w】,按下空格 输入箭头直线段的宽度,指定起点宽度这里我们以100为…...

如何使用CAD编辑器来画箭头
我们在CAD图纸中一般都是看见有很多的指示箭头,在图纸中能够起到很好的指示作用。那么,如何使用CAD编辑器来画箭头呢?相信很多的小伙伴们都想要知道具体的操作方法,那下面小编本编教程就来教教大家,希望对你们有帮助&a…...

天正引出标注lisp_CAD中怎么画引出标注?
展开全部做法标注、引出标注都是天正命令的名称,在CAD中全部是用多重引线来完成。32313133353236313431303231363533e78988e69d8331333433646436先说天正,比较简单。做法标注:天正菜单中,符号标注——做法标注,出现对话…...

cad的半截箭头快捷键
le...

lisp画弯箭头_AutoCAD中怎么画箭头 CAD画箭头的方法
看到网上很多人不知道CAD怎么画箭头的方法,AutoCAD中怎么画箭头?其实在CAD中绘制箭头的方法很多,CAD培训的老师就自己常用的方法说说吧:1.如果你要标注的话,系统会自动画出箭头,如果想改变箭头的大小可以在-------修改----箭头文字…...

vue 运行项目浏览器页面显示“该网页无法正常运作”
项目运行成功并自动弹出 但是页面上显示: 确定问题: 检查build/webpack.dev.conf.js文件中是否存在下面代码: disableHostCheck: true, https: true,如果有的话,确定一下是否用的https进行的访问,如果用https进行访…...

asp.net 调试 无法显示该网页
在用VS2008调试网站的时候,突然页面不能正常显示了,IE显示“无法显示该网页”。 症状一: IE地址栏里面显示的端口号和桌面任务栏右下角“ASP.NET Development Server”的端口不一致,而把IE地址栏的端口号改成“ASP.NET Develo…...
SAP F1 无法显示该网页 完美解决方案(不用重装SAP)
SAP F1或HTML页面都找不到页面完美解决方案(不用重装SAP) 问题截图: 图一 原因: 无法显示该网页,最近总被这样的问题困扰,这几天重装两次发现,偶尔用电脑管家清理一下病毒,总是发现有这样的信息存在&…...

vs无法显示该网页
看了这篇文章(http://hi.baidu.com/leilongbing/blog/item/fa3a3253a39f0a060df3e3f1.html)解决了问题: 调试Web程序的时候,突然页面不能显示出来,老是显示着“网页无法显示”的页面。云里雾里,鬼知道是怎…...
准备转行入坑iOS开发的大灯,第一步-第一篇:基本要求和技术趋势
毛笔照片 - 加上直式文字,更显中国水墨风说到App开发的工作时常令人兴奋,而且报酬也好。可以创造令人惊叹的产品,让人们的生活更美好,并在一个舒适温暖的办公室里度过一整天... 梦想总是美好的。如果没有开始行动,梦终…...

解决关于腾讯会议黑屏问题(ThinkpadE420型号)
近期,由于2020年1月的疫情影响,开学时间一度被延期,毕设答辩被安排到线上,学院安排使用 腾讯会议app进行线上答辩。然而在测试阶段发现问题,打开页面出现黑屏问题,现就解决方案分享给出现类似问题的你。 问…...

iPad 3 即将发布,网传价格,IPD2降价50$ 新功能猜测
中关村在线消息:近几日苹果 iPad 3明显受到了更多用户的关注,互联网中关于此款 产品的消息早已被传的沸沸扬扬,之前曾有国外媒体曝出 苹果iPad 3将会于3月9日发布,这个时间与 iPad 2的发布时间相差无几,而今天我们也发…...

苹果gamecenter未能连接服务器,win7系统GameCenter无法连接服务器的解决方法
很多小伙伴都遇到过win7系统GameCenter无法连接服务器的困惑吧,一些朋友看过网上零散的win7系统GameCenter无法连接服务器的处理方法,并没有完完全全明白win7系统GameCenter无法连接服务器是如何解决的,今天小编准备了简单的解决办法…...

windows无法连接到打印机
项目场景:windows无法连接到打印机 windows无法连接到打印机。本地打印后台处理程序服务没有运行。请重新启动打印机后台处理程序或重新启动计算机 问题描述 解决方案: 搜索服务,点击打开 搜索Print Spooler 查看状态是否运行,…...

win7进去提醒未能连接一个服务器,win7系统提示“未能连接一个windows服务”这个情况如何解决...
win7系统提示“未能连接一个windows服务”这个情况如何解决发布时间:2020-01-14小编:yongzhi浏览数:最近呢,小编收到了一些小伙伴的来信,他们说:重装win7系统过后,就会弹出一个“未能连接一个wi…...

电脑显示未连接一个服务器怎么处理,Win7开机提示“未能连接一个windows服务”的解决方法...
最近有一位Win7系统用户,开机之后系统出现提示“未能连接一个windows服务”,上面显示Windows无法连接到System Event Notification Service服务,肯定是服务项出现了问题。那么我们该如何解决这个问题?下面装机之家分享一下Win7开机…...

老是未能连接一个window服务器,未能连接一个Windows服务 怎么回事
打开【运行】,然后输入CMD;输入【NETSH WINSOCK RESET CATALOG】命令,然后重新启动【System Event Notification Service】服务;输入【NETSH WINSOCK RESET CATALOG】命令;如果不行在安全模式上输入重启。以下是详细介…...

HarmonyOS内核(Lite-mOS)开发——任务管理
任务管理简介基本概念 1、从系统的角度看,任务是竞争系统资源的最小运行单元。任务可以使用或等待CPU、使用内存空间等系统资源,并独 立于其它任务运行。 2、LiteOS的任务模块可以给用户提供多个任务,实现了任务之间的切换和通信,…...