面试问题
IT类
Task和Thread有什么区别
- 任务可以返回结果,没有直接的机制可以从线程返回结果。
- 任务通过使用取消令牌来支持取消,但是线程没有。
- 一个任务可以同时执行多个线程,线程一次只能运行一个任务。
- 可以使用async和await关键字轻松实现异步。
- 新的Thread不处理线程池线程,而Task确实使用线程池线程。
- 任务是比线程更高层次的概念。
Thread
是基于操作系统级别的线程,而ThreadPool
和Task
不会创建自己的操作系统线程,二者是由任务调度器(TaskScheduler
)执行,默认的调度程序仅仅在ThreadPool
上运行,与ThreadPool
不同,Task
可以在指定时间返回完成结果,并且还可以通过ContinueWith
延续任务,以使得任务执行完毕后运行更多操作,如果已完成立即进行回调,也可以调用Wait
来同步等待任务完成,如同Thread.Join
一样阻塞线程执行,直到任务完成
由于任务在ThreadPool
上运行,因此创建不加任何选项的默认Task
并不适用于执行长时间的操作,因为它们可能会将系统默认的线程池给填满导致其他操作的线程阻塞,但是Task
提供了LongRunning
选项,设置此项后,告诉任务调度器(TaskScheduler
)启动新的线程,而不是在ThreadPool
上运行
反射有什么用
获取已装载类的成员变量信息;
获取已装载类的方法;
获取已装载类的构造方法信息。
委托有什么用
其实C#中的委托是用来实现传递回调函数的
C#是一个强类型语言需要标识这个回调函数的形参类型
如何配置Spring数据库
pom配置spring-boot-starter-jdbc
xml
线程和进程的区别
本质区别:进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
包含关系:一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
资源开销:每个进程都有独立的地址空间,进程之间的切换会有较大的开销;线程可以看做轻量级的进程,同一个进程内的线程共享进程的地址空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。
影响关系:一个进程崩溃后,在保护模式下其他进程不会被影响,但是一个线程崩溃可能导致整个进程被操作系统杀掉,所以多进程要比多线程健壮.
什么是多态
动态多态(dynamic polymorphism):通过类继承机制和虚函数机制生效于运行期。可以优雅地处理异质对象集合,只要其共同的基类定义了虚函数的接口。也被称为子类型多态(Subtype polymorphism)或包含多态(inclusion polymorphism)。在面向对象程序设计中,这被直接称为多态。
静态多态(static polymorphism):模板也允许将不同的特殊行为和单个泛化记号相关联,由于这种关联处理于编译期而非运行期,因此被称为“静态”。可以用来实现类型安全、运行高效的同质对象集合操作。C++STL不采用动态多态来实现就是个例子。
全局变量
滥用全局变量会造成不必要的常量频繁使用,特别当这个常量没有用宏定义“正名”时,代码阅读起来将万分吃力。
全局变量的作用域是在整个工程文件内都有效
Redis如何保证缓冲与数据库数据的一致性
读写双写策略:当数据需要更新时,先更新数据库,再更新 Redis 缓存。这样可以确保数据库和缓存中的数据一致。
失效策略:当数据库中的数据被更新时,立即使对应的 Redis 缓存失效。这样下次读取时,Redis 将从数据库中重新加载最新数据并进行缓存。这种策略适用于数据更新频率低的情况。
延迟双删策略:当数据需要更新时,首先删除 Redis 缓存中的数据,然后更新数据库。在读取数据时,如果发现 Redis 缓存已经失效,则从数据库中重新加载数据并进行缓存。这种策略可以减轻数据库压力,并确保数据的一致性。
更新队列策略:将数据更新操作放入一个消息队列中,由消费者负责更新数据库和 Redis 缓存。这种方式可以异步地更新数据库和缓存,提高系统的响应速度,并减少数据库的负载。
采用数据库级别的缓存解决方案:有些数据库(例如 MySQL)提供了内置的缓存机制,可以直接使用数据库的缓存功能,这样可以避免 Redis 缓存与数据库的一致性问题。
C#进程间的通讯方式
共享内存、Pipe、和Channel、Socket
长连接和短连接
长连接实现原理
长连接的主要特色是连接的长时间保持,那么就存在如下几个问题要解决:
- 长连接如何建立?
答:长连接的建立需要依赖TCP三次握手建立起可靠的连接
- 长连接如何释放?
答:长连接的释放需要依赖TCP的四次挥手,释放连接
- 长连接如何保活(双方都活着时保持连接,一方不存活时断开连接)
答:在不进行业务数据传输的时候,一端会定时发送探活(心跳)报文,如果接受到ack报文,则表明对端可正确提供服务。那多长时间发送一次探活报文(保活时间)?如果探活报文没有被正确回复,探活报文会重复多少次(探活次数)?探活报文间隔多长时间发一次(探活间隔)?
- 一个服务最多能保持多少个长连接
答:只能说很多很多,这和机器的性能(内存大小),机器的设置(文件最大打开数)有关系,具体计算方式我也还没有弄清楚,可参看参考文献
- 长连接的安全性如何?
答:长连接建立连接后一直保持,一般认为安全性较差
长连接应用
长连接适合操作频繁的点对点通信,例如:数据库连接等,省去短连接每次建立连接释放连接的资源和时间
什么是短连接
短连接是和长连接相对的概念,短连接是指每次传输数据之前都要在双方新建一个连接,在数据传输完成后,该连接断开,也就是短连接只能进行一项业务数据的发送。
短连接实现原理
http的短连接是基于TCP的短连接,不需要进行三次握手连接的建立和四次挥手连接的释放,在需要进行数据交换时,建立连接,交换结束后中断连接
短连接应用
web网的http服务一般都是使用短链接,web服务一般并发量大,如果都使用长连接,会占用非常多的资源
系统文件和库文件
文件系统把数据组织成相互独立的数据文件,实现了记录内的结构性,但整体无结构;而数据库系统实现整体数据的结构化。
在文件系统中,数据冗余度大,浪费存储空间,容易造成数据的不一致,但是在数据库系统中,数据是面向整个系统,数据可以被多个用户、多个应用共享使用,减少了数据冗余。文件系统中的文件是为某一特定应用服务的,当要修改数据的逻辑结构时,必须修改应用程序,修改文件结构的定义,数据和程序之间缺乏独立性,数据库系统中,通过DBMS的两级映象实现了数据的物理独立性和逻辑独立性,把数据的定义从程序中分离出去,减少了应用程序的维护和修改。
什么时候用递归
这些被处理的对象之间是有规律的递增或递减
有明确的结束条件
Unity 判断面前有多少怪物
的少两人人的TransForm后 通过视距,视野角度 确定 敌人是否在视野中
唯一ID怎么生成
UUID
网卡、当地时间、一个随记数来生成UUID。
优点:
- 代码实现简单
- 本地生成,没有性能问题,没有高可用风险
- 全球唯一的,数据迁移容易
缺点:
- 长度过长,存储冗余,且无序不可读,查询效率低
- 每次生成的ID是无序的,不满足趋势递增
- UUID是字符串,而且比较长,占用空间大,查询效率低
- ID没有含义,可读性差
自增ID
- 优点:数据库生成的ID绝对有序,高可用实现方式简单
- 缺点:需要独立部署数据库实例,成本高,有性能瓶颈
SnowFlake
以时间戳+机器+递增序列
优点:本地生成,不依赖中间件。 生成的分布式id足够小,只有8个字节,而且是递增的
能满足高并发分布式系统环境下ID不重复
生成效率高
基于时间戳,可以保证基本有序递增
不依赖于第三方的库或者中间件
生成的id具有时序性和唯一性
缺点:时钟回拨问题,强烈依赖于服务器的时间,如果时间出现时间回拨 就可能出现重复的id
堆和栈的区别
栈(stack)和堆(heap)都是内存中的一段区域,但它们的内存分配方式是不同的。栈是由程序自动创建和释放的,通常用于存储函数调用时的临时变量、函数的返回地址等信息。而堆则是由程序员手动申请和释放的,通常用于存储程序中需要动态分配的内存(如动态数组、对象等)。
栈的内存分配是按照“后进先出”的原则进行的,即最后一个进入栈的变量最先被释放。因此,栈中的内存管理是由系统自动完成的,程序员不需要过多考虑内存的分配和释放问题。堆的内存管理则需要程序员自行负责,使用完毕后必须手动释放,否则会导致内存泄漏或其他问题。
栈的容量较小,一般只有几百KB到几MB的空间,具体容量由操作系统和编译器决定。相对而言,堆用于存储较大的数据结构,大小一般比栈要大得多,可以动态扩展内存空间。但是,因为堆需要手动管理内存,如果不及时释放,会导致内存泄漏,进而影响系统性能。
电气类
plc的两种类型
整体式和分布式