线程实现
python 的 thread 模块是比较底层的模块,threading 模块是对 thread 做了一些封装的,可以更好的使用
说明:python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程
多线程执行
# coding=utf-8 import threading import time class HelloWorld(threading.Thread): def run(self): print(f"hello, world ~, my name is{self.name}") time.sleep(1) if __name__ == '__main__': for i in range(5): hello_obj = HelloWorld() hello_obj.start()
可以看到同时打印了 hello, world ~,还有自己的 name(Thread-id);当调用 start() 时,才会真正的创建线程,并且开始执行
主线程会等待所有的子线程结束后才结束
# coding=utf-8 import threading import time class HelloWorld(threading.Thread): def __init__(self, num): threading.Thread.__init__(self) self.second = num def run(self): print(f"hello, world ~, my name is{self.name}") time.sleep(self.second) if __name__ == '__main__': for i in range(5): hello_obj = HelloWorld(i) hello_obj.start() while True: # 查看当前运行的线程数量 length = len(threading.enumerate()) print(f"current running thread num is:{length}") if length <= 3: break time.sleep(1)
总结:
- 每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的name,但是python会自动为线程指定一个名字
- 当线程的run()方法结束时该线程完成
- 无法控制线程调度顺序,但可以通过别的方式来影响线程调度的方式
多线程-共享全局变量
在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
from threading import Thread import time g_num = 100 class Work1(Thread): def run(self): global g_num for i in range(3): g_num += 1 print(f"----in work1, g_num is {g_num}---") class Work2(Thread): def run(self): global g_num print(f"----in work2, g_num is {g_num}---") print(f"---线程创建之前g_num is {g_num}---") t1 = Work1() t1.start() # 延时一会,保证t1线程中的事情做完 time.sleep(1) t2 = Work2() t2.start()
多线程开发可能遇到的问题
假设两个线程 t1 和 t2 都要对全局变量 g_num (默认是0)进行加1运算,t1 和 t2 都各对 g_num 加10次,g_num 的最终的结果应该为 20
但是由于是多线程同时操作,有可能出现下面情况:
- 在 g_num=0 时,t1 取得 g_num=0。此时操作系统把 t1 调度为”sleeping”状态,把 t2 转换为”running”状态,t2 也获得 g_num=0
- 然后 t2 对得到的值进行加1并赋给 g_num,使得 g_num=1
- 然后操作系统又把 t2 调度为”sleeping”,把 t1 转为”running”,线程 t1 又把它之前得到的0加1后赋值给 g_num
- 这样导致虽然 t1 和 t2 都对 g_num 加1,但结果仍然是 g_num=1
# coding=utf-8 import time import threading from threading import Thread g_num = 0 class Work1(Thread): def __init__(self, count): Thread.__init__(self) self.count = count def run(self): global g_num for i in range(self.count): g_num += 1 # print(f"----in work1, g_num is {g_num}---") class Work2(Work1): pass print(f"---线程创建之前g_num is {g_num}---") count = 1000000 t1 = Work1(count) t1.start() t2 = Work2(count) t2.start() while len(threading.enumerate()) != 1: time.sleep(1) print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num) 运行结果 ---线程创建之前g_num is 0--- 2个线程对同一个全局变量操作之后的最终结果是:1275729
如果多个线程同时对同一个全局变量操作,会出现资源竞争问题,从而数据结果会不正确