@@ -543,14 +543,15 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
543
543
count = sum(range(0,101))
544
544
print(count)
545
545
```
546
+
546
547
# Python高级
547
548
## 4设计模式
548
549
## 4.1 对设计模式的理解,简述你了解的设计模式?
549
- 设计模式是经过总结,优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码,反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。
550
- 常见的是工厂模式和单例模式
550
+ 设计模式是经过总结,优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码,反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。
551
+ 常见的是工厂模式和单例模式
551
552
552
553
## 4.2 请手写一个单例
553
- ```
554
+ ```
554
555
#python2
555
556
class A(object):
556
557
__instance = None
@@ -560,14 +561,16 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
560
561
return cls.__instance
561
562
else:
562
563
return cls.__instance
563
- ```
564
+ ```
564
565
## 4.3 单例模式的应用场景有那些?
565
- 单例模式应用的场景一般发现在以下条件下:
566
+ 单例模式应用的场景一般发现在以下条件下:
566
567
资源共享的情况下,避免由于资源操作时导致的性能或损耗等,如日志文件,应用配置。
567
568
控制资源的情况下,方便资源之间的互相通信。如线程池等,1,网站的计数器 2,应用配置 3.多线程池 4数据库配置 数据库连接池 5.应用程序的日志应用...
569
+
568
570
## 4.5 对装饰器的理解,并写出一个计时器记录方法执行性能的装饰器?
569
- 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
570
- ```
571
+ 装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。
572
+
573
+ ```
571
574
import time
572
575
def timeit(func):
573
576
def wrapper():
@@ -579,41 +582,41 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
579
582
@timeit
580
583
def foo():
581
584
print('in foo()'foo())
582
- ```
585
+ ```
583
586
## 4.6 解释以下什么是闭包?
584
- 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
587
+ 在函数内部再定义一个函数,并且这个函数用到了外边函数的变量,那么将这个函数以及用到的一些变量称之为闭包。
585
588
586
589
## 4.7 函数装饰器有什么作用?
587
- 装饰器本质上是一个python函数,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景。比如:插入日志,性能测试,事务处理,缓存。权限的校验等场景,有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
590
+ 装饰器本质上是一个python函数,它可以在让其他函数在不需要做任何代码的变动的前提下增加额外的功能。装饰器的返回值也是一个函数的对象,它经常用于有切面需求的场景。比如:插入日志,性能测试,事务处理,缓存。权限的校验等场景,有了装饰器就可以抽离出大量的与函数功能本身无关的雷同代码并发并继续使用。
588
591
## 4.8 生成器,迭代器的区别?
589
- 迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身,对于string,list,dict,tuple等这类容器对象,使用for循环遍历是很方便的,在后台for语句对容器对象调用iter()函数,iter()是python的内置函数,iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数,在没有后续元素时,next()会抛出一个StopIteration异常。
592
+ 迭代器是一个更抽象的概念,任何对象,如果它的类有next方法和iter方法返回自己本身,对于string,list,dict,tuple等这类容器对象,使用for循环遍历是很方便的,在后台for语句对容器对象调用iter()函数,iter()是python的内置函数,iter()会返回一个定义了next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是python的内置函数,在没有后续元素时,next()会抛出一个StopIteration异常。
590
593
生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用yield语句。每次next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
591
594
区别: 生成器能做到迭代器能做的所有事,而且因为自动创建iter()和next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出StopIteration异常。
592
595
## 4.9 X是什么类型?
593
596
X= (fo ri in ramg(10))
594
597
X是 generator类型
595
598
## 4.10 请用一行代码 实现将1-N 的整数列表以3为单位分组
596
- ```
599
+ ```
597
600
print ([[x for x in range(1,100)] [i:i+3] for i in range(0,len(list_a),3)])
598
- ```
601
+ ```
599
602
## 4.11 Python中yield的用法》
600
- yield就是保存当前程序执行状态。你用for循环的时候,每次取一个元素的时候就会计算一次。用yield的函数叫generator,和iterator一样,它的好处是不用一次计算所有元素,而是用一次算一次,可以节省很多空间,generator每次计算需要上一次计算结果,所以用yield,否则一return,上次计算结果就没了
603
+ yield就是保存当前程序执行状态。你用for循环的时候,每次取一个元素的时候就会计算一次。用yield的函数叫generator,和iterator一样,它的好处是不用一次计算所有元素,而是用一次算一次,可以节省很多空间,generator每次计算需要上一次计算结果,所以用yield,否则一return,上次计算结果就没了
601
604
## 7系统编程
602
605
## 7.1 进程总结
603
- 进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid。
606
+ 进程:程序运行在操作系统上的一个实例,就称之为进程。进程需要相应的系统资源:内存、时间片、pid。
604
607
创建进程:
605
608
首先要导入multiprocessing中的Process:
606
609
创建一个Process对象;
607
610
创建Process对象时,可以传递参数;
608
- ```
611
+ ```
609
612
p = Process(target=XXX,args=(tuple,),kwargs={key:value})
610
613
target = XXX 指定的任务函数,不用加(),
611
614
args=(tuple,)kwargs={key:value}给任务函数传递的参数
612
- ```
613
- 使用start()启动进程
615
+ ```
616
+ 使用start()启动进程
614
617
结束进程
615
618
给子进程指定函数传递参数Demo
616
- ```
619
+ ```
617
620
import os
618
621
from mulitprocessing import Process
619
622
import time
@@ -632,8 +635,8 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
632
635
#1秒钟之后,立刻结束子进程
633
636
p.terminate()
634
637
p.join()
635
- ```
636
- 注意:进程间不共享全局变量
638
+ ```
639
+ 注意:进程间不共享全局变量
637
640
进程之间的通信-Queue
638
641
在初始化Queue()对象时(例如q=Queue(),若在括号中没有指定最大可接受的消息数量,获数量为负值时,那么就代表可接受的消息数量没有上限一直到内存尽头)
639
642
Queue.qsize():返回当前队列包含的消息数量
@@ -647,7 +650,7 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
647
650
如果block值为False,消息队列如果没有空间可写入,则会立刻抛出"Queue.Full"异常;
648
651
Queue.put_nowait(item):相当Queue.put(item,False)
649
652
进程间通信Demo:
650
- ```
653
+ ```
651
654
from multiprocessing import Process.Queue
652
655
import os,time,random
653
656
#写数据进程执行的代码:
@@ -680,9 +683,9 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
680
683
#pr 进程里是死循环,无法等待其结束,只能强行终止:
681
684
print('')
682
685
print('所有数据都写入并且读完')
683
- ```
684
- 进程池Pool
685
- ```
686
+ ```
687
+ 进程池Pool
688
+ ```
686
689
#coding:utf-8
687
690
from multiprocessing import Pool
688
691
import os,time,random
@@ -702,11 +705,11 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
702
705
po.close()
703
706
po.join()
704
707
print("----end----")
705
- ```
706
- 进程池中使用Queue
708
+ ```
709
+ 进程池中使用Queue
707
710
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到如下的错误信息:
708
711
RuntimeError: Queue objects should only be shared between processs through inheritance
709
- ```
712
+ ```
710
713
from multiprocessing import Manager,Pool
711
714
import os,time,random
712
715
def reader(q):
@@ -728,23 +731,23 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
728
731
po.close()
729
732
po.join()
730
733
print("(%s)End"%os.getpid())
731
- ```
734
+ ```
732
735
## 7.2 谈谈你对多进程,多线程,以及协程的理解,项目是否用?
733
- 这个问题被问的概念相当之大,
736
+ 这个问题被问的概念相当之大,
734
737
进程:一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所有进程间数据不共享,开销大。
735
738
线程: cpu调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在,一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
736
739
协程: 是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操中栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
737
740
738
741
## 7.3 Python异常使用场景有那些?
739
- 异步的使用场景:
742
+ 异步的使用场景:
740
743
1、 不涉及共享资源,获对共享资源只读,即非互斥操作
741
744
2、 没有时序上的严格关系
742
745
3、 不需要原子操作,或可以通过其他方式控制原子性
743
746
4、 常用于IO操作等耗时操作,因为比较影响客户体验和使用性能
744
747
5、 不影响主线程逻辑
745
748
746
749
## 7.4 多线程共同操作同一个数据互斥锁同步?
747
- ```
750
+ ```
748
751
import threading
749
752
import time
750
753
class MyThread(threading.Thread):
@@ -765,18 +768,18 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
765
768
t.start()
766
769
if __name__=="__main__":
767
770
test()
768
- ```
771
+ ```
769
772
## 7.5 什么是多线程竞争?
770
- 线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全
773
+ 线程是非独立的,同一个进程里线程是数据共享的,当各个线程访问数据资源时会出现竞争状态即:数据几乎同步会被多个线程占用,造成数据混乱,即所谓的线程不安全
771
774
那么怎么解决多线程竞争问题?---锁
772
775
锁的好处: 确保了某段关键代码(共享数据资源)只能由一个线程从头到尾完整地执行能解决多线程资源竞争下的原子操作问题。
773
776
锁的坏处: 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
774
777
锁的致命问题: 死锁
775
778
## 7.6 请介绍一下Python的线程同步?
776
- 一、 setDaemon(False)
779
+ 一、 setDaemon(False)
777
780
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行的最小单位,当设置多线程时,主线程会创建多个子线程,在Python中,默认情况下就是setDaemon(False),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束。
778
781
例子
779
- ```
782
+ ```
780
783
import threading
781
784
import time
782
785
@@ -794,11 +797,11 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
794
797
#执行结果
795
798
---主线程--结束
796
799
---子线程结束---
797
- ```
798
- 二、 setDaemon(True)
800
+ ```
801
+ 二、 setDaemon(True)
799
802
当我们使用setDaemon(True)时,这是子线程为守护线程,主线程一旦执行结束,则全部子线程被强制终止
800
803
例子
801
- ```
804
+ ```
802
805
import threading
803
806
import time
804
807
def thread():
@@ -814,13 +817,13 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
814
817
main()
815
818
#执行结果
816
819
---主线程结束--- #只有主线程结束,子线程来不及执行就被强制结束
817
- ```
818
- 三、 join(线程同步)
820
+ ```
821
+ 三、 join(线程同步)
819
822
join 所完成的工作就是线程同步,即主线程任务结束以后,进入堵塞状态,一直等待所有的子线程结束以后,主线程再终止。
820
823
当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序,所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和,简单的来说,就是给每个子线程一个timeou的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。
821
824
没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。
822
825
例子
823
- ```
826
+ ```
824
827
import threading
825
828
import time
826
829
@@ -839,12 +842,12 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
839
842
840
843
if __name__=='__main___':
841
844
main()
842
- ```
845
+ ```
843
846
## 7.7 解释以下什么是锁,有哪几种锁?
844
- 锁(Lock)是python提供的对线程控制的对象。有互斥锁,可重入锁,死锁。
847
+ 锁(Lock)是python提供的对线程控制的对象。有互斥锁,可重入锁,死锁。
845
848
846
849
## 7.8 什么是死锁?
847
- 若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
850
+ 若干子线程在系统资源竞争时,都在等待对方对某部分资源解除占用状态,结果是谁也不愿先解锁,互相干等着,程序无法执行下去,这就是死锁。
848
851
GIL锁 全局解释器锁(只在cython里才有)
849
852
作用: 限制多线程同时执行,保证同一时间只有一个线程执行,所以cython里的多线程其实是伪多线程!
850
853
所以python里常常使用协程技术来代替多线程,协程是一种更轻量级的线程。
@@ -855,38 +858,38 @@ New 是真正创建实例对象的方法,所以重写基类的new 方法,以
855
858
创建一个已访问数据列表,用于存储已经访问过的数据,并加上互斥锁,在多线程访问数据的时候先查看数据是否在已访问的列表中,若已存在就直接跳过。
856
859
857
860
## 7.10 什么是线程安全,什么是互斥锁?
858
- 每个对象都对应于一个可称为’互斥锁‘的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
861
+ 每个对象都对应于一个可称为’互斥锁‘的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
859
862
同一进程中的多线程之间是共享系统资源的,多个线程同时对一个对象进行操作,一个线程操作尚未结束,另一线程已经对其进行操作,导致最终结果出现错误,此时需要对被操作对象添加互斥锁,保证每个线程对该对象的操作都得到正确的结果。
860
863
861
864
## 7.11说说下面几个概念:同步,异步,阻塞,非阻塞?
862
- 同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。
865
+ 同步: 多个任务之间有先后顺序执行,一个执行完下个才能执行。
863
866
异步: 多个任务之间没有先后顺序,可以同时执行,有时候一个任务可能要在必要的时候获取另一个同时执行的任务的结果,这个就叫回调!
864
867
阻塞: 如果卡住了调用者,调用者不能继续往下执行,就是说调用者阻塞了。
865
868
非阻塞: 如果不会卡住,可以继续执行,就是说非阻塞的。
866
869
同步异步相对于多任务而言,阻塞非阻塞相对于代码执行而言。
867
870
868
871
## 7.12 什么是僵尸进程和孤儿进程?怎么避免僵尸进程?
869
- 孤儿进程: 父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init 进程(进程号为1)所收养,并由init 进程对他们完成状态收集工作。
872
+ 孤儿进程: 父进程退出,子进程还在运行的这些子进程都是孤儿进程,孤儿进程将被init 进程(进程号为1)所收养,并由init 进程对他们完成状态收集工作。
870
873
僵尸进程: 进程使用fork 创建子进程,如果子进程退出,而父进程并没有调用wait 获waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中的这些进程是僵尸进程。
871
874
避免僵尸进程的方法:
872
875
1.fork 两次用孙子进程去完成子进程的任务
873
876
2.用wait()函数使父进程阻塞
874
877
3.使用信号量,在signal handler 中调用waitpid,这样父进程不用阻塞
875
878
## 7.13 python中进程与线程的使用场景?
876
- 多进程适合在CPU密集操作(cpu操作指令比较多,如位多的的浮点运算)。
879
+ 多进程适合在CPU密集操作(cpu操作指令比较多,如位多的的浮点运算)。
877
880
多线程适合在IO密性型操作(读写数据操作比多的的,比如爬虫)
878
881
879
882
## 7.14 线程是并发还是并行,进程是并发还是并行?
880
- 线程是并发,进程是并行;
883
+ 线程是并发,进程是并行;
881
884
进程之间互相独立,是系统分配资源的最小单位,同一个线程中的所有线程共享资源。
882
885
883
886
## 7.15 并行(parallel)和并发(concurrency)?
884
- 并行: 同一时刻多个任务同时在运行
887
+ 并行: 同一时刻多个任务同时在运行
885
888
并发: 在同一时间间隔内多个任务都在运行,但是并不会在同一时刻同时运行,存在交替执行的情况。
886
889
实现并行的库有: multiprocessing
887
890
实现并发的库有: threading
888
891
程序需要执行较多的读写、请求和回复任务的需要大量的IO操作,IO密集型操作使用并发更好。
889
892
CPU运算量大的程序,使用并行会更好
890
893
## 7.16 IO密集型和CPU密集型区别?
891
- IO密集型: 系统运行,大部分的状况是CPU在等 I/O(硬盘/内存)的读/写
894
+ IO密集型: 系统运行,大部分的状况是CPU在等 I/O(硬盘/内存)的读/写
892
895
CPU密集型: 大部分时间用来做计算,逻辑判断等CPU动作的程序称之CPU密集型。
0 commit comments