• 常见面试题


    1、手写代码实现冒泡排序?

    def bubbleSort(nums):

       for i in range(len(nums)-1): # 这个循环负责设置冒泡排序进行的次数

        for j in range(len(nums)-i-1): # j为列表下标

          if nums[j] > nums[j+1]:

            nums[j], nums[j+1] = nums[j+1], nums[j]

      return nums

    nums = [5,2,45,6,8,2,1]

    print bubbleSort(nums)

    2、Scrapy怎么设置深度爬取 

    深度爬虫:针对其实url地址进行数据采集,在响应数据中进行数据筛选得到需要进行数据采集的下一波url地址,并将url地址添加到数据采集队列中进行二次爬取,以此

    类推深度爬虫可以通过不同的方式实现,在urllib2和requesets模块中通过轮询数据筛选得到目标url地址,然后进行循环爬取数据即可,在scrapy中主要通过两种方式

    进行处理:

    1.通过Response对象的地址序列和Request对象的请求处理完成深度采集


    2.通过CrawlSpider类型中的请求链接提取规则自动进行深度数据采集处理

    深度爬虫的应用:

    (1)、通过Response对象和Request完成深度数据采集

    Request对象:

      是scrapy框架的核心对象,通过将字符串url地址包装成请求对象交给调度器进行调度管理,然后交给下载模块进行 数据采集

    (2)、Spider CrawlSpider完成数据深度爬取

    • scrapy框架对于深度爬虫,提供了一种封装类scrapy.CrawlSpider,当我们开发时继承这个类,就能使用scrapy框架封装好的各种深度爬虫功能
    • scrapy.CrawlSpider是从scrapy.Spider继承并进行功能扩展的类,主要通过定义url地址提取规则,跟踪链接地址,从而进行深度的数据采集

    3、django关闭浏览器,怎么清除cookies和session?

    SESSION_EXPIRE_AT_BROWSER_CLOSE=True;//在配置文件配置,可是该方式无效;

     

    另一种方式:request.session.set_expiry(0);那么当浏览器关闭时,session失效,试验成功;

     

    备注:

     

    一、request.session.set_expiry(value);可以传递四种不同的值给它:

     

      * 如果value是个整数,session会在些秒数后失效。

      * 如果value是个datatime或timedelta,session就会在这个时间后失效。

      * 如果value是0,用户关闭浏览器session就会失效。//我们用的就是这种方式

      * 如果value是None,session会依赖全局session失效策略。

     

    二、django有四中session实现方式

     

      1、数据库(database-backed sessions)//默认的方式

      2、缓存(cached sessions)

      3、文件系统(file-based sessions)

      4、cookie(cookie-based sessions)//php是基于这种方式的

    4、MVT是什么?

       M 全拼为 Model,与 MVC 中的 M 功能相同,负责和数据库交互,进行数据处理。

       V 全拼为 View,与 MVC 中的 C 功能相同,接收请求,进行业务处理,返回应答。

       T 全拼为 Template,与 MVC 中的 V 功能相同,负责封装构造要返回的 html。

     

       

      1.用户点击注册按钮,将要注册的内容发送给网站的服务器。

     

      2.view视图接收到用户发来的注册数据,View告诉Model将用户的注册信息保存进数据库。

     

      3,Model层将用户的信息保存到数据库中。

     

      4.数据库将保存的结果返回给Model

     

      5,Mode将保存的结果给View视图。

     

      6,view视图告诉Template模板去产生一个html界面。

     

      7,Templage生成html内容返回给view视图

     

      8,view视图将html界面内容返回给浏览器

     

      9,浏览器拿到view返回的html页面内容进行解析,展示。

     

    5、怎样解决数据库高并发的问题?

      一个项目刚开始的时候是为了实现基本功能,随着版本和功能的迭代,大数据和高并发成了软件设计必须考虑的问题!

      本质很简单,一个是慢,一个是等。

      两者是相互关联的,因为慢,所以要等,因为等,所以慢,解决了慢,也就解决了等,解决了等,也就解决了慢。

      关键是如何解决慢和等,核心一个是,一个是,一个是分流,最后一个是集群/横向扩张/读写分离/建立主从

    短是指路径要短:

    典型的mvc结构是请求->controller->model->dao->view,然后把页面返回给用户。要想短的话,

      1,页面静态化- 用户可以直接获取页面,不用走那么多流程,比较适用于页面不频繁更新。

      2,使用缓存- 第一次获取数据从数据库准提取,然后保存在缓存中,以后就可以直接从缓存提取数据。不过需要有机制维持缓存和数据库的一致性。

      3,使用储存过程-那些处理一次请求需要多次访问数据库的操作,可以把操作整合到储存过程,这样只要一次数据库访问就可以了。

      4,批量读取 - 高并发情况下,可以把多个请求的查询合并到一次进行,以减少数据库的访问次数

      5,延迟修改 - 高并发情况下,可以把多次修改请求,先保存在缓存中,然后定时将缓存中的数据保存到数据库中,风险是可能会断电丢失缓存中的数据,

      6,  使用索引 - 索引可以看作是特殊的缓存,尽量使用索引就要求where字句中精确的给出索引列的值。

    少是指查询的数据要少:

      1,分表 - 把本来同一张表的内容,可以按照地区,类别等分成多张表,很简单的一个思路,但是要尽量避免分出来的多表关联查询。

      2,分离活跃数据 - 例如登录用户业务,注册用户很多,但是活跃的登录用户很少,可以把活跃用户专门保存一张表,查询是先查询活跃表,没有的话再查总表,这也类似与缓存啦。

      3, 分块 - 数据库层面的优化,对程序是透明的,查询大数据只用找到相应块就行。

     分流三种:

      1,集群 - 将并发请求分配到不同的服务器上,可以是业务服务器,也可以是数据库服务器。

      2,分布式 - 分布式是把单次请求的多项业务逻辑分配到多个服务器上,这样可以同步处理很多逻辑,一般使用与特别复杂的业务请求。

      3,CDN - 在域名解析层面的分流,例如将华南地区的用户请求分配到华南的服务器,华中地区的用户请求分配到华中的服务器。

    6、事务的特性?

    事务具有四个特征:原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability )。这四个特性简称为 ACID 特性。

    1) .原子性 

      事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做 

    2 ).一致性 

      事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据

    库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或

    者说是 不一致的状态。

    3) .隔离性 

      一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。 

    4) .持续性 

      也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。 

     

    数据库系统必须维护事务的以下特性 ( 简称 ACID) : 

     

      事务中的所有操作要么全部执行,要么都不执行; 

      如果事务没有原子性的保证,那么在发生系统 ;

      故障的情况下,数据库就有可能处于不一致状态

    7、apache和nginx的区别

    Nginx

     

    1. 轻量级,采用 C 进行编写,同样的 web 服务,会占用更少的内存及资源

    2. 抗并发,nginx 以 epoll and kqueue 作为开发模型,处理请求是异步非阻塞的,负载能力比 apache 高很多,而 apache 则是阻塞型的。在高并发下 nginx 能保持低资源低消耗高性能 ,而 apache 在 PHP 处理慢或者前端压力很大的情况下,很容易出现进程数飙升,从而拒绝服务的现象。

    3. nginx 处理静态文件好,静态处理性能比 apache 高三倍以上

    4. nginx 的设计高度模块化,编写模块相对简单

    5. nginx 配置简洁,正则配置让很多事情变得简单,而且改完配置能使用 -t 测试配置有没有问题,apache 配置复杂 ,重启的时候发现配置出错了,会很崩溃

    6. nginx 作为负载均衡服务器,支持 7 层负载均衡

    7. nginx 本身就是一个反向代理服务器,而且可以作为非常优秀的邮件代理服务器

    8. 启动特别容易, 并且几乎可以做到 7*24 不间断运行,即使运行数个月也不需要重新启动,还能够不间断服务的情况下进行软件版本的升级

    9. 社区活跃,各种高性能模块出品迅速

     

    Apache

     

    1. apache 的 rewrite 比 nginx 强大,在 rewrite 频繁的情况下,用 apache

    2. apache 发展到现在,模块超多,基本想到的都可以找到

    3. apache 更为成熟,少 bug ,nginx 的 bug 相对较多

    4. apache 超稳定

    5. apache 对 PHP 支持比较简单,nginx 需要配合其他后端用

    6. apache 在处理动态请求有优势,nginx 在这方面是鸡肋,一般动态请求要 apache 去做,nginx 适合静态和反向。

    7. apache 仍然是目前的主流,拥有丰富的特性,成熟的技术和开发社区

     

    总结

     

    两者最核心的区别在于 apache 是同步多进程模型,一个连接对应一个进程,而 nginx 是异步的,多个连接(万级别)可以对应一个进程

     

    一般来说,需要性能的 web 服务,用 nginx 。如果不需要性能只求稳定,更考虑 apache ,后者的各种功能模块实现得比前者,例如 ssl 的模块就比前者好,可配置项多。

    epoll(freebsd 上是 kqueue ) 网络 IO 模型是 nginx 处理性能高的根本理由,但并不是所有的情况下都是 epoll 大获全胜的,如果本身提供静态服务的就只有寥寥几个文件,apache

    的 select 模型或许比 epoll 更高性能。当然,这只是根据网络 IO 模型的原理作的一个假设,真正的应用还是需要实测了再说的。

     

    更为通用的方案是,前端 nginx 抗并发,后端 apache 集群,配合起来会更好。

    8、长链接与短链接的区别?

    在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他

    类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。

     

    而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:

     

    Connection:keep-alive
    

     

    在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已

    经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持

    长连接。

     

    HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。

     发送接收方式 

    1、异步 

      报文发送和接收是分开的,相互独立的,互不影响。这种方式又分两种情况: 

      (1)异步双工:接收和发送在同一个程序中,由两个不同的子进程分别负责发送和接收 

      (2)异步单工:接收和发送是用两个不同的程序来完成。 

    2、同步 

      报文发送和接收是同步进行,既报文发送后等待接收返回报文。 同步方式一般需要考虑超时问题,即报文发出去后不能无限等待,需要设定超时时间,超过

    该时间发送方不再等待读返回报文,直接通知超时返回。 
      
    在长连接中一般是没有条件能够判断读写什么时候结束,所以必须要加长度报文头。读函数先是读取报文头的长度,再根据这个长度去读相应长度的报文。 

    9、Post和get区别?

      1、get用于获取数据,post用于提交数据

     

      2、get提交参数追加在url后面,post参数可以通过http body提交

     

      3、get的url会有长度上的限制,则post的数据则可以非常大

     

      4、get提交信息明文显示在url上,不够安全,post提交的信息不会在url上显示

     

      5、get提交可以被浏览器缓存,post不会被浏览器缓存

    10、Tcp协议和udp协议有什么区别?

      TCP协议---传输控制协议

     

      UDP协议---用户数据报协议  

    TCP协议

     

      1)面向连接的可靠的传输控制协议,连接的建立需要三次握手,连接的释放需要进行四次握手才能保证连接的建立,数据的同步传输。

     

      2)面向字节流,会把从上层传输下来的数据当作是无结构的字节流。

     

      3)一对一的通信。

     

      4)TCP在IP协议的基础之上添加了序号机制,确认机制,超时重传机制,数据校验,从而保证传输的可靠性,同时保证不出现丢失或者是乱序。

    UDP协议

      1)无连接的数据包服务,一方向另一方发送数据不需要建立连接。相当于发短信,别人是否收到,短信信息是否丢失都不能知道。

      2)面向报文的,从上层接收的数据如果报文不大于传输限制,则直接加上首部传输,如果报文过大,则进行IP分片后,再分别加入首部进行传输。

      3)UDP协议可以一对一通信,同时可以一对多通信。

      4)UDP仅仅是尽最大的努力进行交付,只是做比较初级的检查,比如端头检查,差错检测,往往在传输过程中会出现分组丢失、乱序、重复传输等问题。

    总结:虽然UDP是不可靠的,但是在一些应用场景下对可靠传输的要求不高的情况下,UDP协议具有更好的实时性,工作效率要比TCP高。同时,UDP的段结构要比TCP的段结

    构简单,能降低网络开销。

    补充:

    • TCP(transport control protocol,传输控制协议)是面向连接的,面向流的,提供高可靠服务。收发两端都要有一一成对的socket,因此,发送端为了将多个发往接收端包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据,合并成一个大的数据块,然后进行封包。这样,接收端就难于分辨出来了,必须提供科学的拆包机制。即面向流的通信是无消息保护边界的。
    • UDP(user datagram protocol,用户数据报协议)是无连接的,面向消息的,提供高效率服务。不会使用块的合并优化算法,由于UDP支持的是一对多的模式,所以接收端的skbuff(套接字缓冲区)采用了链式结构来记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址,端口等信息),这样对于接收端来说,就容易进行区分处理了。即面向消息的通信是有消息保护边界的。

     

    11、Python中有日志吗?怎么使用?

       这个当然有了,Python有自带的logging模块,用于记录日志

    一、日志级别(从低到高):

     

      DEBUG :详细的信息,通常只出现在诊断问题上

     

      INFO:确认一切按预期运行

     

      WARNING:一个迹象表明,一些意想不到的事情发生了,或表明一些问题在不久的将来(例如。磁盘空间低”)。这个软件还能按预期工作。

     

      ERROR:更严重的问题,软件没能执行一些功能

     

      CRITICAL :一个严重的错误,这表明程序本身可能无法继续运行

     

    注:这5个等级,也分别对应5种打日志的方法: debug 、info 、warning 、error 、critical。默认的是WARNING,当在WARNING或之上时才被跟踪。

     

    二、日志输出:显示到控制台或保存到文件中,可以灵活选用

     

    # 这里为了简便,同时处理:输出控制台和保存到文件中

    import logging  

    # 第一步,创建一个logger  
      logger = logging.getLogger()  

      logger.setLevel(logging.INFO)  # Log等级总开关  

    # 第二步,创建一个handler,用于写入日志文件  
      logfile = './log.txt'  

      fh = logging.FileHandler(logfile, mode='a')  # open的打开模式这里可以进行参考

      fh.setLevel(logging.DEBUG)  # 输出到file的log等级的开关  

    # 第三步,再创建一个handler,用于输出到控制台  
      ch = logging.StreamHandler()  

      ch.setLevel(logging.WARNING)   # 输出到console的log等级的开关  


    # 第四步,定义handler的输出格式  
      formatter = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")  

      fh.setFormatter(formatter)  

      ch.setFormatter(formatter)  

    # 第五步,将logger添加到handler里面  
      logger.addHandler(fh)  

      logger.addHandler(ch)  

    # 日志  
      logger.debug('这是 logger debug message')  

      logger.info('这是 logger info message')  

      logger.warning('这是 logger warning message')  

      logger.error('这是 logger error message')  

      logger.critical('这是 logger critical message')

    三、日志格式说明

     

      logging.basicConfig函数中,可以指定日志的输出格式format,这个参数可以输出很多有用的信息,如下:

     

      %(levelno)s: 打印日志级别的数值

     

      %(levelname)s: 打印日志级别名称

     

      %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]

     

      %(filename)s: 打印当前执行程序名

     

      %(funcName)s: 打印日志的当前函数

     

      %(lineno)d: 打印日志的当前行号

     

      %(asctime)s: 打印日志的时间

     

      %(thread)d: 打印线程ID

     

      %(threadName)s: 打印线程名称

     

      %(process)d: 打印进程ID

     

      %(message)s: 打印日志信息

    12、手写单例模式代码?

    class SingleTon(object):
      def __new__(cls, *args, **kwargs):
        if not hasattr(cls,'_instance'):
          cls._instance = object.__new__(cls,*args,**kwargs)
        return cls._instance

    class TestClass(SingleTon):
      a = 1

    test1 = TestClass()
    test2 = TestClass()

    print test1.a, test2.a
    print id(test1),id(test2)

  • 相关阅读:
    leetcode Lowest Common Ancestor of a Binary Tree
    leetcode 141、Linked list cycle
    leetcode 136、Single Number
    tensorflow使用
    c++ priority_queue
    python语法
    CSS基础之选择器
    并发编程的一些理解
    封装的绑定与多态
    继承与派生
  • 原文地址:https://www.cnblogs.com/yao950814/p/10266299.html
Copyright © 2020-2023  润新知