关于Rust引用与指针的讨论

关于Rust引用与指针的讨论 在Rust/CPP中,我们会学习到一个新概念叫做引用,这是对指针的更高级别抽象,引用可以看作对一个对象的别名,相当于你用一个别名来代替原对象并进行相关操作,而且不会内存占用且在函数传参时不会发生内存拷贝。引用相比于指针,更能实现安全的内存操作。这也是为什么rust会采用引用作为指针的抽象。 引用的最大特点是初始化引用后不能修改引用的指向,这样极大的保证了不会出现指针的访问无效内存。 在b站上有个人针对初始化后不能改变引用的指向这句话发出了反驳,是rust代码,代码如下: 1 2 3 4 5 fn main() { let mut r=&0; let a=&7; r=&a; } 他指出此代码中r被定义为可变引用,第三行可以改变原引用的指向,因此可以推导出引用初始化后可以改变。 错误在哪呢? 首先我们要了解rust的引用与解引用和CPP的引用和其他语言的取地址符号的关系。rust的&操作其实是与cpp不同,cpp分左值引用与右值引用,在讨论类似的左值引用时,cpp的格式如下 1 2 3 4 int main(){ int a=1; int &b=a; } 在这个例子中,我们知道rust的可变引用就是实现在借用时改变能借用数据,在此时实例中r 为字面量0的可变引用,可是对字面量的可变引用意义在哪?字面量值是不可更改的! 那么如何去理解这个可变引用? rust官方给出两个名词叫做引用与解引用,可以将&理解为cpp的取地址符,这里声明了一个变量r用于存储字面量0的地址,a用于存储字面量7的内存地址,然后将a的内存地址赋给r,第三行r的内容变为了a字面量的地址。

July 3, 2023 · 1 min · 37 words · ecturing

Token与Cookie+Session区别

Token与Cookie+Session区别 在了解Token与Cookie+Session技术的直接区别之前,需要了解HTTP协议,以下是MDN的介绍: HTTP 是无状态的:在同一个连接中,两个执行成功的请求之间是没有关系的。这就带来了一个问题,用户没有办法在同一个网站中进行连续的交互,比如在一个电商网站里,用户把某个商品加入到购物车,切换一个页面后再次添加了商品,这两次添加商品的请求之间没有关联,浏览器无法知道用户最终选择了哪些商品。而使用 HTTP 的标头扩展,HTTP Cookie 就可以解决这个问题。把 Cookie 添加到标头中,创建一个会话让每次请求都能共享相同的上下文信息,达成相同的状态。 HTTP 最早期的模型和 HTTP/1.0 的默认模型,是短连接。每一个 HTTP 请求都由它自己独立的连接完成;这意味着发起每一个 HTTP 请求之前都会有一次 TCP 握手,而且是连续不断的。 在传统Cookie+Session中,当向服务器请求验证后,当登录成功服务端会生成Session,并将SessionId通过Set-Cookie发送给客户端,然后客户端将Cookie保存后,后续每次进行请求时,会携带Cookie一起发送给服务端,服务端验证Cookie中的SessionId后(即鉴权)再予以相应操作。 在Token请求中,与Cookie+Session类似,在向服务器请求验证后,服务器会对当用户生成一个唯一Id即token,这个token即代表着这个用户,服务端将token传输给客户端,后面客户端请求时带上这个token就行,后续请求时,服务端只需要验证token库中是否存在当前token即可完成验证。 注意MDN这一句话:同一个链接中,两个执行成功地请求之间是没有关系的。正因为HTTP的无状态,请求之间无关,在类似WebSocket的长连接中,通常使用Session来管理服务端与客户端的链接,在HTTP下是不需要的。因为无状态,所以每次请求都会携带token,使用在服务端只需要验证token的状态即可实现鉴权,同时使用Token与Session相比,Session中参数更多,保存需要更多的空间,而Token可以是一个字符串或数字,空间占用远小于session所占用的空间。

April 20, 2023 · 1 min · 23 words · ecturing

Gos+Drone+Docker实现持续部署

Gos+Drone+Docker实现持续部署 使用Docker-Compose实现Gos+Drone+DockerRunner的部署 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 version: "3" services: gogs: restart: always image: gogs/gogs container_name: gogs ports: - "6022:22" - "6023:3000" volumes: - /var/gogs:/data/gogs #配置文件映射 - /home/gogs/data:/data/git/gogs-repositories #Git仓库映射 drone-server: image: drone/drone:2 container_name: drone-server environment: - TZ=Asia/Shanghai - DRONE_GOGS_SERVER=http://gogs:3000 #Gogs服务地址 - DRONE_GIT_ALWAYS_AUTH=false #可选的布尔值将 Drone 配置为在克隆公共存储库时进行身份验证 - DRONE_RPC_SECRET=XXXXXXXXXXXXXXX - DRONE_SERVER_HOST=drone....

April 11, 2023 · 1 min · 124 words · ecturing

IO模型分析

IO模型分析 本文主要讲的是网络IO技术,在网络IO中常见模型有五种BIO,NIO,AIO,I/O multiplexing,Signal driven I/O,分别对应的是阻塞IO,非阻塞IO,异步IO,IO多路复用,信号驱动IO。本文主要讲述阻塞IO与三种IO多路复用 BIO 常见阻塞式IO即一个线程对应一个IO处理,当IO事件阻塞时,当前线程也一起阻塞,直到IO事件就绪。这种IO效率较为低下,在等待IO就绪期间线程一直处于阻塞状态,线程利用率低。此种IO模型除开初学者进行多线程IO训练,使用较少。 Select select属于NIO的一种,属于非阻塞式IO,无需实现多个线程等待多个IO事件的就绪,select会维护一个名叫fd_set的事件描述符数组。 每一次需要发起IO请求时,就加入一个事件描述符到管道中,然后由select函数进行管道的遍历,不断的轮询管道中各个IO事件的状态,当出现某个IO事件状态为就绪时,就进行此IO事件的处理,这样多个线程的IO阻塞模型转换为IO的多路复用,也就是只需阻塞一个线程,监听管道描述符的IO事件状态,当有就绪事件时并进行处理,减少了IO事件未就绪时线程等待的开销,极大的提高了系统的性能。 Poll poll函数为select函数的升级版,在select函数中维护了事件描述符数组,然而数组必须规定数组长度,无法像链表一样实现可增长。因此poll函数在用户态维护了描述符数组,在内核态处理IO操作时,将其转换为链表,这样就摆脱了最大文件描述符数量的限制。但是poll和select中内核态与用户态的拷贝带来性能损失问题始终没有解决。 Epoll epoll是一种更为高效的多路复用技术,也是Nginx服务器能处理高流量背后的技术支撑他最大的特点就是解决了select和poll中描述符序列中携带未就绪序列导致浪费的问题。他直接将描述符序列插入到内核中的epoll_event的红黑树描述符序列中,选择红黑树的原因是由于描述符序列需要频繁的查找,插入,删除,红黑树是最好的选择。 红黑树是一种自平衡二叉查找树,具有以下优点: 任何一个节点的左右子树的高度差不超过一倍。 查找、插入、删除操作的时间复杂度都是 $O(log n)$。 它能够快速地支持区间查找和排序等操作。 内核对红黑树中文件描述符进行监听,在使用 epoll_wait 等待事件时,可以指定一个回调函数,该函数将在事件到达时被调用,当事件触发后,内核会调用该回调进行操作。 epoll中水平触发和垂直触发 水平触发 当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用epoll_ wait 时,会再次响应应用程序并通知此事件。 边缘触发 当epoll_wait检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_ wait 时,不会再次响应应用程序并通知此事件。例如这次没有把数据全部读写完(如读写缓冲区太小),那么下次调用epoll_wait()时,它不会通知你,也就是它只会通知你一次,直到该文件描述符上出现第二次可读写事件才会通知你。

March 3, 2023 · 1 min · 32 words · ecturing

并发编程

并发编程 以下是一些常用的并发编程模型和技术: 信号量(Semaphore):用于保护共享资源、协调进程间同步和互斥操作的机制,可以限制对某个共享资源的访问数量。 锁:在多线程或多进程的环境中,如果多个线程或进程同时访问共享数据,可能会导致数据不一致或竞争条件等问题,从而影响程序的正确性和可靠性。为了解决这些问题,可以使用锁来同步多个线程或进程之间对数据的访问,锁一般分为两种,互斥锁和读写锁。 原子操作(Atomic Operation):通过CPU提供的原子指令(例如Compare-and-swap、Fetch-and-add等)来对内存进行原子操作,从而避免并发情况下的数据竞争。 事件驱动(Event-driven):使用消息队列、事件循环等机制,将任务分解为小而独立的事件单元,并通过异步调用来执行这些事件单元,以提高程序的并发性能。 Actor模型:基于对象的并发编程模型,通过创建多个Actor对象,每个对象都有自己的状态和行为,可以相互发送消息来进行通信和协作。 协程(Coroutine):一种轻量级的线程,可以在一个或多个线程中执行,通过协作式调度的方式实现非抢占式的多任务处理,从而提高程序的并发性能。 数据流(Dataflow):使用管道、通道等机制,将数据从一个任务顺序传递到另一个任务,以实现并发数据处理。 锁 自旋锁:即CAS 读写锁:常见IO操作中的读写锁 互斥锁: 信号量: 事件驱动 数据流 数据流模型是go语言中最常见的一个模型,它使用了select加channel的方法实现了数据流模型,每一份数据就像水流一样流动。 原子操作

January 9, 2023 · 1 min · 19 words · ecturing