一、多线程
每个进程至少都有一个线程,而这个线程就是我们通常说的主线程,创建的子线程共享主线程之间的数据,所有线程之间操作共享的数据就需要同步与互斥
1.1 创建线程
导入线程模块
import threading
参数说明
Thread([group [, target [, name [, args [, kwargs]]]]])
- group: 线程组,目前只能使用None
- target: 执行的目标任务名
- args: 以元组的方式给执行任务传参
- kwargs: 以字典方式给执行任务传参
- name: 线程名,一般不用设置
import threading
import time
# 带有参数的任务
def task(name, count):
for i in range(count):
print(f"{name}任务执行中..")
time.sleep(0.2)
else:
print(f"{name}任务执行完成")
if __name__ == '__main__':
# 创建子进程
# args: 以元组的方式给任务传入参数
sub_thread1 = threading.Thread(target=task, args=('xiaoming', 5))
sub_thread2 = threading.Thread(target=task, kwargs={'name': 'xiaozhang', 'count': 5})
sub_thread1.start()
sub_thread2.start()
sub_thread1.join()
sub_thread2.join()
1.2 继承方式创建线程
from threading import Thread
import time
import os
class MyThread(Thread):
def __init__(self, name, count):
Thread.__init__(self)
self.name = name
self.count = count
def run(self):
for i in range(self.count):
print(f"{self.name}任务执行中..")
time.sleep(0.2)
else:
print(f"{self.name}任务执行完成")
if __name__ == '__main__':
# 创建子进程
# args: 以元组的方式给任务传入参数
sub_thread1 = MyThread('xiaoming', 5)
sub_thread2 = MyThread('xiaozhang', 5)
sub_thread1.start()
sub_thread2.start()
sub_thread1.join()
sub_thread2.join()
print('主线程结束')
线程创建和继承创建多么的相似,不同之处在于线程是共享数据,进程是拷贝数据
1.3 互斥锁
线程之间访问共享资源,需要加互斥锁,避免出现同时访问共享资源的时候,出现问题
互斥锁:
lock = threading.Lock()
lock.acquire()
#共享资源
lock.release()
或者使用上下文
with lock:
#共享资源
实例:
import threading
import time
lock = threading.Lock()
num = 0
def incre(count):
global num
while count > 0:
with lock:
num += 1
count -= 1
time.sleep(0.1)
def main():
threads = []
for i in range(5):
thread = threading.Thread(target=incre, args=(100,))
thread.start()
threads.append(thread)
for thread in threads:
thread.join()
print("expected value is", 5 * 100, "real value is", num)
if __name__ == '__main__':
main()
- 互斥锁的作用就是保证同一时刻只能有一个线程去操作共享数据,保证共享数据不会出现错误问题
- 使用互斥锁会影响代码的执行效率,但避免同时访问数据出现问题
- 互斥锁如果没有使用好容易出现死锁的情况
1.4 线程安全的队列
Queue 模块实现了线程安全的队列,尤其适合多线程编程, 是最简单也是最常用的队列
Queue Queue : 一个先进先出( FIFO )的队列,最先加入队列的元素最先取出;
LifoQueue LifoQueue : 一个后进先出( LIFO )的队列,最后加入队列的元素最先取出;
PriorityQueue PriorityQueue :优先级队列,队列中的元素根据优先级排序 。
Queue:
import threading
import time
import random
from queue import Queue
class Producer(threading.Thread):
"""
Producer thread 制作线程
"""
def __init__(self, t_name, myqu): # 传入线程名、实例化队列
threading.Thread.__init__(self, name=t_name) # t_name即是threadName
self.data = myqu
def run(self):
for i in range(5): # 生成0-4五条队列
print("%s: %s is producing %d to the queue!" % (time.ctime(), self.getName(), i)) # 当前时间t生成编号d并加入队列
self.data.put(i) # 写入队列编号
time.sleep(random.randint(1,10) / 5) # 随机休息一会
#print("%s: %s producing finished!" % (time.ctime(), self.getName)) # 编号d队列完成制作
class Consumer(threading.Thread):
def __init__(self, t_name, myqu):
threading.Thread.__init__(self, name=t_name)
self.data = myqu
def run(self):
for i in range(5):
val = self.data.get()
print("%s: %s is consuming. %d in the queue is consumed!" % (\
time.ctime(), self.getName(), val)) # 编号d队列已经被消费
time.sleep(random.randint(1,10))
#print("%s: %s consuming finished!" % (time.ctime(), self.getName())) # 编号d队列完成消费
if __name__ == '__main__':
myqueue= Queue()
productThread = Producer('ProducerThread', myqueue)
comsumerThread = Consumer('comsumerThread', myqueue)
productThread.start()
comsumerThread.start()
productThread.join()
comsumerThread.join()