Python的多线程
pyhton的多线程,在多个进程之间反复切换形成类似多线程的效果,是虚假的多线程,是由GIL锁造成的。
在当前线程进程遇到IO操作时,会将GIL释放,由其他线程争取,当前线程不参与争夺。当线程超时时,GIL也会释放,当前线程也会参与争夺。
在多线程环境中,Python虚拟机的执行过程:
设置GIL锁
切换线程
运行
设置线程睡眠
解锁GIL锁
重复以上过程
GIL锁
存在于CPython和Ruby中,一般安装python时,默认安装CPyhon。
在多线程情况下,只有当线程获得GIL的时候,代码才能够运行,但全局锁只有一个,所以同时只能有一个线程运行。
深拷贝和浅拷贝
对于不可变对象(数字,字符串,元组,不可变集合等),深拷贝和浅拷贝并无区别,都是建立一个指向不可变对象的指针
a = [[1, 2], 'str']
在对a进行浅拷贝时,获得的对象地址与a是不同的
b = copy.copy(a)
print(id(a) == id(b)) # False
但是列表元素地址相同
b = copy.copy(a)
print(id(a[0]) == id(b[0])) # True
若对a列表元素进行修改,b列表元素也会发生改变
a.append(3)
print(b) # [[1, 2], 'str', 3]
在对a进行深拷贝时,获得的对象地址与a也是不同的
c = copy.deepcopy(a)
print(id(a) == id(c)) # False
但元素地址不同
b = copy.copy(a)
print(id(a[0]) == id(b[0])) # False
同时,若对a列表元素进行修改,b列表元素不会发生改变
a.append(3)
print(b) # [[1, 2], 'str']
深拷贝会把可变对象也拷贝一份,而浅拷贝不会,这是二者之间最明显的区别
类
构造函数
构造函数也被称为构造器,当创建对象的时候第一个被自动调用的函数。在同一个类中,构造函数只能出现一次
class Check():
num1 = 0
s1 = "str"
def __init__(self):
self.dic = {'name': 'Tony'}
self.fun1()
def func1(self):
self.num2 = 2
return self.num2
def func2(self):
self.num3 = 23
return self.num3
def ___del__(self):
print('done')
类变量
这里的num1和s1即为类变量,当通过类修改类变量时,实例的类变量也会发生变化,反之通过实例修改类变量时,类的类变量不会发生变化
check_one = Check()
Check.num1 = 1
print(chekc_one.num1, Check.num1) # 1, 1
check_one.s1 = 'str1'
print(chekc_one.s1, Check.s1) # str1, str
成员变量(实例变量)
只有在 __init__中的,形似self.xxx的变量,或是在__init__中调用函数的变量,才是真正意义上的成员变量,成员变量的作用域是整个类
在 Check类中,self.dic、self.num2为成员变量
构造方法调用
若一个类继承了n(0-∞)个类,在子类中调用父类的构造方法有两种方式:
class People:
def __init__(self, name, age):
self.name = name
self.age = age
class Work(People):
def __init__(self, name, age, department):
People.__init__(self, name, age)
self.grade = grade
析构函数
当程序结束运行或是对象被删除时,会调用析构函数,释放内存
check_one = Check()
print('last word')
# 'last word'
# 'done'
check_two = Check()
del check_two
print('last word ')
# 'done'
# 'last word twice'
类方法、实例方法、静态方法
class Kls(object):
def foo(self, x):
print('executing foo(%s,%s)' % (self, x))
@classmethod
def class_foo(cls,x):
print('executing class_foo(%s,%s)' % (cls,x))
@staticmethod
def static_foo(x):
print('executing static_foo(%s)' % x)
ik = Kls()
# 实例方法
ik.foo(1)
# 类方法
ik.class_foo(1)
Kls.class_foo(1)
# 静态方法
ik.static_foo(1)
Kls.static_foo('hi')
调用实例方法时,会将ik作为self参数传入foo;调用类方法时,会将Kls作为参数传入class_foo;调用静态方法时,无需传入实例或类