概述
python3中建议用threading,原先的thread重命名为_thread。在python中多线程并没有那么有效,因为GIL的存在所以线程也没法做到真正的并发,但对于IO比较频繁的程序,多线程还是能很好的起作用的。
补充:背的时候觉得自己总能记住但是过几个星期又忘了…
并发: 宏观角度同时而微观顺序。
并行:微观同时。
一些基本操作
获取已激活的线程数
threading.active_count()
# 2
查看所有线程信息
threading.enumerate()
查看现在正在运行的线程
threading.current_thread()
添加线程
def thread_job():
print('This is a thread of %s' % threading.current_thread())
def main():
thread = threading.Thread(target=thread_job) # 定义线程,常用参数还有args和name,分别是传给target的参数和给这个线程取得名字
thread.start() # 让线程开始工作
thread.join() # 不加join则程序会往下走,尽管线程还没运行完
if __name__ == '__main__':
main()
关于join
被调用 join() 方法的线程会一直阻塞调用者的线程,直到自己结束。
当你想要线程A B都结束之后主函数才运行,比如print(“done”)时,你可以选择join。
而当你想让线程和主线程同时运行的时候不要加入join。比如当你把playsound加入线程并join后,主线程会暂停,直到音乐播完,所以这种情况我们不应该join()
join与否是关键,若处理不好则会变得和单线程没有区别。
Lock
thread_lock = threading.Lock() # 实例一个lock
代码分析(失败)
这段代码还有些许疑问
- 为什么C阻塞的时候线程A B不会获得CPU呢?
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : therading_test.py
# @Author: wfxt
# @Date : 2019/11/28
# @Desc :
import threading
import time
outside_x = 0
outside_y = 0
class MyThread(threading.Thread): # 继承threading模块中的Thread类(类的首字母大写)
def __init__(self, name, x, y, rest_time):
threading.Thread.__init__(self) # 继承Thread的构造函数
self.name = name
self.x = x
self.y = y
self.rest_time = rest_time
def update_x(self, x):
print("开始线程: " + self.name)
# thread_lock_x.acquire()
self.x = x
global outside_x
print(self.name, "休息", str(self.rest_time), "s...")
time.sleep(self.rest_time)
outside_x = self.x
# thread_lock_x.release()
print("outside x,y:", outside_x, outside_y)
print(self.name + " 结束")
def update_y(self, y):
print("开始线程: " + self.name)
# thread_lock_y.acquire()
self.y = y
global outside_y
print(self.name, "休息", str(self.rest_time), "s...")
time.sleep(self.rest_time)
outside_y = self.y
# thread_lock_y.release()
print("outside x,y:", outside_x, outside_y)
print(self.name + " 结束")
def sum_outside_xy():
sum_xy = outside_x + outside_y
print("outside x,y:", outside_x, outside_y)
print("sum:", sum_xy)
thread_lock_x = threading.Lock()
thread_lock_y = threading.Lock()
threads = []
def main():
threadA = MyThread("Thread-A", 1, 2, 0.5)
threadB = MyThread("Thread-B", 4, 5, 1)
threadC = MyThread("Thread-C", 7, 8, 5)
threads.append(threadA)
threads.append(threadB)
threads.append(threadC)
for thread in threads:
thread.start()
thread.deamon = True
# thread.join()
threadC.update_x(77)
threadA.update_x(11)
threadB.update_y(88)
sum_outside_xy()
if __name__ == '__main__':
main()
写这段代码的时候要吐了,运行结果如下(加不加锁运行都一样),C在暂停了5s后才开始的A,这就是python的GIL作怪了
Thread-C 休息 5 s...
outside x,y: 77 0
Thread-C 结束
开始线程: Thread-A
Thread-A 休息 0.5 s...
outside x,y: 11 0
Thread-A 结束
开始线程: Thread-B
Thread-B 休息 1 s...
outside x,y: 11 88
Thread-B 结束
outside x,y: 11 88
sum: 99
代码分析
global_n = 0
def job1():
global global_n
for i in range(10):
global_n += 1
print('job1', global_n)
def job2():
global global_n
for i in range(10):
global_n += 10
print('job2', global_n)
t1 = threading.Thread(target=job1)
t2 = threading.Thread(target=job2)
t1.start()
t2.start()
# t1.join() # 这里join与否都可能会乱序
# t2.join()
有时候乱序,有时候正常
job1 1
job1 2
job1job2 3
13job1
job2 14
job1 24
job225
job1 3536
job1
job2 4737
job1 48
job1 49
job1 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110
当我们加入锁之后
thread_lock_n = threading.Lock()
def job1():
global global_n
thread_lock_n.acquire()
for i in range(10):
global_n += 1
print('job1', global_n)
thread_lock_n.release()
def job2():
global global_n
thread_lock_n.acquire()
for i in range(10):
global_n += 10
print('job2', global_n)
thread_lock_n.release()
显示永远是正常的
job1 1
job1 2
job1 3
job1 4
job1 5
job1 6
job1 7
job1 8
job1 9
job1 10
job2 20
job2 30
job2 40
job2 50
job2 60
job2 70
job2 80
job2 90
job2 100
job2 110