并发和并行
并发:指的是指的是任务数多于cpu的核数,通过操作系统的调度,实现多个任务一起执行,是一种伪装的一起执行,实际上是在各个人物之间快速调度。
并行:指的是任务数小于cpu的核数,任务是真的一起执行。
线程
线程指的是在程序的运行过程中,执行程序代码的一个分支,每个运行的程序至少有一个线程(主线程)。
多线程执行任务的代码
#导入线程模块
import threading
import time
#定义一个唱歌的任务
def sing(sum):
for i in range(sum):
print('正在唱歌。。。%d' % i)
time.sleep(1)
#定义一个跳舞的方法
def dance(sum):
for i in range(sum):
print('正在跳舞。。。%d' % i)
time.sleep(1)
if __name__ == '__main__':
#创建唱歌的线程
sing_thread = threading.Thread(target=sing,args=(3,))
#创建跳舞的线程
dance_thread = threading.Thread(target=dance,kwargs={'num':3})
#开启线程
sing_thread.start()
dance_thread.start()
补充说明
线程类Thread的参数:
group:线程组,目前只能使用None。
target:执行的目标任务名。
args:以元组的方式传参。
kwargs:以字典的方式传参。
name:线程名,一般不设置。
获取当前线程号的方法:threading.current_thread()
获取当前活动的线程列表:threading.enumerate()
线程注意点:
1.线程之间的执行是无序的。
2.主线程会等待所有的子线程执行结束之后才结束。
3.守护主线程:就是指主线程退出之后,子线程直接销毁,不会继续执行子线程代码。
守护主线程方式1:
设置线程的时候,在指定目标任务名后,添加参数daemon=True
守护主线程方式2:
线程名.setDaemon=True
4.线程之间是共享全局变量的。
自定义线程
import threading
# 自定义线程类
class MyThread(threading.Thread):
# 通过构造方法取接收任务的参数
def __init__(self, info1, info2):
# 调用父类的构造方法
super(MyThread, self).__init__()
self.info1 = info1
self.info2 = info2
# 定义自定义线程相关的任务
def test1(self):
print(self.info1)
def test2(self):
print(self.info2)
# 通过run方法执行相关任务
def run(self):
self.test1()
self.test2()
# 创建自定义线程
my_thread = MyThread("测试1", "测试2")
# 启动
my_thread.start()
#在自定义线程中不能指定target方法,因为自定义线程里面的任务都是在run方法中执行。
启动线程同一使用start方法,不能调用类中定义的run方法,因为run调用启动会导致线程在主线程中执行的。
线程共享全局变量的问题
线程之间由于是共享全局变量,但是当多个线程同时操作全局变量,那么会导致出现问题。因此我们就需要保证在一个时刻只能有一个线程是使用并操作这个全局变量。
线程同步
1.线程等待(主线程会等待第一个线程执行结束之后,再执行接下来的代码或者接下来的线程,从而保证只有一个线程在执行)
线程名.join()
2.互斥锁(对共享的数据进行锁定,抢到锁的行程才能够去操作这个变量)
threading模块中定义了Lock变量,本质是一个函数,可以方便进行处理锁定。
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
3.死锁(就是指没有在合适的地方释放锁,导致程序无法进行下去)