第二波C#面试题记录

1.如何避免死锁。

    死锁产生的原因是,线程1持有对象A,请求对象B,线程2持有对象B,请求对象A,这种情况可能会产生死锁,如何避免:

  1. 避免多次锁定。尽量避免同一个线程对多个 Lock 进行锁定。例如上面的死锁程序,主线程要对 A、B 两个对象的 Lock 进行锁定,副线程也要对 A、B 两个对象的 Lock 进行锁定,这就埋下了导致死锁的隐患。
  2. 具有相同的加锁顺序。如果多个线程需要对多个 Lock 进行锁定,则应该保证它们以相同的顺序请求加锁。比如上面的死锁程序,主线程先对 A 对象的 Lock 加锁,再对 B 对象的 Lock 加锁;而副线程则先对 B 对象的 Lock 加锁,再对 A 对象的 Lock 加锁。这种加锁顺序很容易形成嵌套锁定,进而导致死锁。如果让主线程、副线程按照相同的顺序加锁,就可以避免这个问题。
  3. 使用定时锁。程序在调用 acquire() 方法加锁时可指定 timeout 参数,该参数指定超过 timeout 秒后会自动释放对 Lock 的锁定,这样就可以解开死锁了。
  4. 死锁检测。死锁检测是一种依靠算法机制来实现的死锁预防机制,它主要是针对那些不可能实现按序加锁,也不能使用定时锁的场景的。
  5. 同时加锁(不推荐)。如果要一定要锁 对象A和B,同时对 这两个对象进行加锁,虽然会造成阻塞,但是不会死锁。

2.高并发的解决方案。

  1. 流量优化:防盗链处理。
  2. 前端优化:减少HTTP请求,合并css或js,添加异步请求,启用浏览器缓存和文件压缩,CDN加速,建立独立图片服务器,
  3. 服务端优化:页面静态化,并发处理,队列处理
  4. 数据库优化:数据库缓存,分库分表,分区操作,读写分离,负载均衡。
  5. web服务器优化:负载均衡,nginx反向代理,7,4层LVS软件

3.索引原理,根据什么创建索引。

原理是  B tree或者B+ tree 或者hash桶,

根据什么创建索引,

当这个语句被频繁用作where条件的查询时,最好创建索引,

当一个字段的列的值很丰富的时候,不是唯一几个值时可以创建索引(比如唯一性太差不适合,例如sex)

更新频率不是十分频繁的时候(如果这个列的数据的变化十分的频繁,那么频繁的更改索引文件,会有更多的消耗)

4.webapi如何解决跨域问题。

addcors,UseCors.

5.webapi请求如何找到action。

 

6.在浏览器输入地址后到页面渲染完成,都发生了什么。

 

1、浏览器(客户端)进行地址解析。

 

2、将解析出的域名进行dns解析。

 

3、通过ip寻址和arp,找到目标(服务器)地址。

 

4、进行tcp三次握手,建立tcp连接。

 

5、浏览器发送数据,等待服务器响应。

 

6、服务器处理请求,并对请求做出响应。

 

7、浏览器收到服务器响应,得到html代码。

 

8、渲染页面。

7. .netcore 和framework的区别,优缺点。

 8.list,arraylist,数组有什么区别,什么时候用。

数组在内存上有个连续的空间,索引速度快,使用前需要定义长度,arraylist 不是强类型,不需要先定义长度,因为储存的都是object,如果类型错误,运行时会报错,使用的时候需要装箱拆箱,

list泛型是强类型,不需要装箱拆箱,在编译时确定类型,也可以动态改变大小。

9.readonly,const,private set 区别。

readonly只能在构造函数和定义时初始化值,const在定义时初始化值,private set可以在本类的方法中修改值。

10聚集索引和非聚集索引。

聚集索引顺序和表数据的物理顺序一致。

11.类似string和stringbuilder的高效代码。

线程池代替线程,能用数组用数组,泛型代替object等等。

12.大批量插入更改数据的方法。

先缓存到datatable中在用SqlBulkCopy一次性插入,或者使用表值函数

13。SQLserver分页方法。

1)

select * from ( 
    select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId from ArtistModels 
  ) as b

      where RowId between 10 and 20 
  ---where RowId BETWEEN 当前页数-1*条数 and 页数*条数---

2)select * from ArtistModels  order by ArtistId offset 4 rows fetch next 5 rows only(SQL2012以上的版本才支持:推荐使用 )

3)select top 3 * from ArtistModels where ArtistId not in (select top 15 ArtistId from ArtistModels) 

14.in和exsist的区别

in 和 exists的区别: 如果子查询得出的结果集记录较少,主查询中的表较大且又有索引时应该用in, 反之如果外层的主查询记录较少,子查询中的表大,又有索引时使用exists。其实我们区分in和exists主要是造成了驱动顺序的改变(这是性能变化的关键),如果是exists,那么以外层表为驱动表,先被访问,如果是IN,那么先执行子查询,所以我们会以驱动表的快速返回为目标,那么就会考虑到索引及结果集的关系了 ,另外IN时不对NULL进行处理。

in 是把外表和内表作hash 连接,而exists是对外表作loop循环,每次loop循环再对内表进行查询。一直以来认为exists比in效率高的说法是不准确的。

如果查询语句使用了not in 那么内外表都进行全表扫描,没有用到索引;而not extsts 的子查询依然能用到表上的索引。所以无论那个表大,用not exists都比not in要快。

15.显示执行计划具体都看那些参数。

面是Sql Server查询数据的五种方式,这对我们理解执行计划非常重要。五种方式如下。

  1. 【Table Scan】:遍历整个表来查找匹配的数据行,速度最慢。
  2. 【Index Scan】:依据索引先从表中过滤出一部分记录,然后再查找所有匹配的数据行。查询速度比Table Scan稍快。
  3. 【Index Seek】:依据索引,定位记录的存放位置,然后再取得记录,因此,其查询速度比前面两种都快。
  4. 【Clustered Index Scan】:按聚集索引(一般是主键)遍历整个表,因为它的记录就是按聚集索引来顺序存放的。注意它与Table Scan的区别,其实它们都是进行全表扫描,只不过Table Scan是不带索引的扫描,而Clustered Index Scan是按聚集索引扫描的。
  5. 【Clustered Index Seek】:聚集索引获取记录,它是直接拿到那条记录,而没有进行全表扫描,因此它的查询速度是最快的。

  当我们查看执行计划结果的时候,如果看到【Table Scan】,说明这个表没有建立任何索引,包括聚集索引。但往往看到更多的是【Clustered Index Scan】,表示该查询还是扫描了速个表,只不过是按聚集索引,实际效果还是和【Table Scan】没什么区别,因此,这时候我们可能要考虑建立'组合字段索引'

16.JavaScript闭包是什么。

17.403和 401的区别。

401是验证错误,或者没有验证,403是通过了验证,但是没有该资源的权限。

18.UDP调用connect有什么作用?connect会阻塞,怎么解决?(设置非阻塞,返回之后用select检测状态)

1:会提升效率.前面已经描述了.2:高并发服务中会增加系统稳定性,

1.使用定时器;(最常用也最有效的一种方法)

2.采用非阻塞模式:设置非阻塞,返回之后用select检测状态。

19.、socket服务端的实现,什么情况下可读?

一、 下列四个条件中的任何一个满足时,socket准备好读: 
 1.socket接收缓冲区中已经接收的数据的字节数大于等于socket接收缓冲区低潮限度的当前值;对这样的socket的读操作不会阻塞,并返回一个大于0的值(即:准备好读入的数据的字节数).我们可以用socket选项SO_RCVLOWAT来设置此低潮限度,对于TCP和UDPsocket,其缺省值为1; 
 2.连接的读这一半关闭(即:接收到对方发过来的FIN的TCP连接).对于这样的socket的读操作将不阻塞,并且返回0(即:文件结束符,FIN包体长度为0字节); 
 3.socket是一个用于监听的socket,并且已经完成的连接数为非0.这样的soocket处于可读状态,是因为socket收到了对方的connect请求,执行了三次握手的第一步:对方发送SYN请求过来,使监听socket处于可读状态;正常情况下,这样的socket上的accept操作不会阻塞; 
 4.有一个socket有异常错误条件待处理.对于这样的socket的读操作将不会阻塞,并且返回一个错误(-1),errno则设置成明确的错误条件.这些待处理的错误也可通过指定socket选项SO_ERROR调用getsockopt来取得并清除; 
  
二、 下列三个条件中的任何一个满足时,socket准备好写 : 
 1.socket发送缓冲区中的可用空间字节数大于等于socket发送缓冲区低潮限度的当前值,且(i):socket已连接(TCP socket),或者(ii):socket不要求连接(如:UDP socket).这意味着,如果我们将这样的socket设置为非阻塞模式,写操作将不会阻塞,并且返回一个正值(如:由传输层接收的字节数).我们可以用socket选项SO_SNDLOWAT来设置此低潮限度,对于TCP和UDP socket,其缺省值一般是2048Bytes; 
 2.连接的写这一半关闭.对于这样的socket的的写操作将产生信号SIGPIPE; 
 3.有一个socket异常错误条件待处理.对于这样的socket的写操作将不会阻塞并且返回一个错误(-1),errno则设置成明确的错误条件.这些待处理的错误也可以通过指定socket选项SO_ERROR调用getsockopt函数来取得并清除;

 20.select和epoll的区别。epoll有哪些触发模式,有什么区别?如果select返回可读,结果只读到0字节,是什么情况?

.select的句柄数目受限,在linux/posix_types.h头文件有这样的声明:#define __FD_SETSIZE    1024  表示select最多同时监听1024个fd。而epoll没有,它的限制是最大的打开文件句柄数目。

2.epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是“活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)。

3.使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。

21.多线程和多进程的区别。

https://www.cnblogs.com/virusolf/p/5458325.html

 22.依赖注入怎么理解,有什么作用。

23.redis数据类型及使用场景。

24.redis存取原理是栈还是队列?

25..net core  token 中间件。

posted @ 2020-09-03 11:36  周小杰  阅读(540)  评论(0编辑  收藏  举报