一:线程:两个函数同时执行
import time
import threading
def sing():
for i in range(5):
print("我正在唱歌......")
time.sleep(1)
def dance():
for i in range(5):
print("我正在跳舞......")
time.sleep(1)
def main():
t1 = threading.Thread(target = sing)
t2 = threading.Thread(target = dance)
t1.start()
t2.start()
if __name__ == "__main__":
main()
单核CPU:同一时间只能做同一件事情。
过程解析:程序一旦启动,立刻会生成一个主线程,当程序运行到t1.start(),的时候程序此时出现有一个子线程,这个子线程会从sing方法开始执行,知道sing方法结束。当主线程运行到t2.start()的时候,程序此时出现有一个子线程,这个子线程会从dance方法开始执行,知道dance方法结束。
二:查看当前线程的运行数:
import threading
def test1():
for i in range(5):
print("------test1---- %d" % i)
def test2():
for i in range(5):
print("------test2---- %d" % i)
def main():
t1 = threading.Thread(target = test1)
t2 = threading.Thread(target = test2)
t1.start()
t2.start()
print(threading.enumerate())
if __name__ == "__main__":
main()
对于这样一个代码,当t1,t2,所在的线程启动时,此时主线程和两个子线程分别强资源,导致打印出的线程可能是主线程也可能是子线程中的任何一个。
如果让test1先执行,然后test2,最后主线程,怎么增加休眠??
import threading
import time
def test1():
for i in range(5):
print("------test1---- %d" % i)
def test2():
for i in range(5):
print("------test2---- %d" % i)
def main():
t1 = threading.Thread(target = test1)
t2 = threading.Thread(target = test2)
t1.start()
# 主线程休眠一秒钟,让t1线程执行完。
time.sleep(1)
t2.start()
# 主线程休眠一秒钟,让t2线程执行完。
time.sleep(1)
# 此时打印的一定是主线程
print(threading.enumerate())
if __name__ == "__main__":
main()
此时的输出应该是:先打印5次test1,再打印5次test2,最后打印出主线程(最后只有主线程)。同样道理,如果要想让t2先执行,只需要 t2.start()先开始,再休眠。t1.start()再开始 ,再休眠即可。但是如果让主线程先执行呢?需要在t1,t2函数内进行延时,此时主线程先死呢还是会等待t1,t2执行完呢?测试:
import threading
def test1():
for i in range(5):
print("------test1---- %d" % i)
time.sleep(1)
def test2():
for i in range(5):
print("------test2---- %d" % i)
time.sleep(1)
def main():
t1 = threading.Thread(target = test1)
t2 = threading.Thread(target = test2)
t1.start()
t2.start()
print(threading.enumerate())
print("主线程执行完了")
if __name__ == "__main__":
main()
这也就是说:在子线程没结束前,主线程不会先执行完,要等子线程执行完,主线程才结束。
子线程什么时间结束?
答:如果创建Threading指定的函数运行结束,那么标志着子线程结束。
三:Thread(target = 函数名),target可不可以指定一个类呢?
特点:这个类必须继承threading.Thread这个类。并且这个类必须具有run方法,因为这个类的对象调用start()方法的时候会默认调用类中的run方法。
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = self.name + ":" + str(i)
print(msg)
# 在run方法里可以调用其他方法,构成整个功能模块。
self.login()
self.register()
def login(slef):
print("这是登录模块的代码....")
def register(self):
print("这是注册模块的代码....")
if __name__ == "__main__":
# 这里定义类的对象,此时子线程没有创建
t = MyThread()
# 当调用start方法的时候子线程创建了,会主动调用run方法
t.start()
问题:在run方法中调用login和redgster是一共三个线程还是只有一个线程???
答:只有一个线程,定义几个MyThread()对象,执行几个start()方法就有几个线程,run方法内是在一个线程内。
四:多线程之间共享全局变量
import threading
import time
g_num = 100
def test1():
global g_num
g_num += 1
print("in test" + g_num)
def test2():
print("out test" + g_num)
def main():
t1 = thread.Thread(target = test1)
t2 = thread.Thread(target = test2)
t1.start()
time.sleep(1)
t2.start()
time.sleep(1)
print("main test" + g_num)
if __name__ == "__main__":
main()
解析:如果多线程之间共享全局变量,则三个都是101,如果不是 则是 101 100 100
即:对于g_num 这个变量,主线程和t1 t2线程,是共享的。
验证:既然是共享变量的,那么也可以将一个数据传给每个线程分别执行呀??
import threading
import time
def test1(temp):
g_num.append(33)
print("-------test1------ %s", str(temp))
def test1(temp):
print("-------test2------ %s", str(temp))
g_num = [11,22]
def main():
# 这里必须传入元组Thread的第二个参数必须是元组
t1 = threading.Thread(target=test1, (g_num,))
t2 = threading.Thread(target=test2, (g_num,))
t1.start()
time.sleep(1)
t2.start()
time.sleep(1)
print("------main---%s", str(g_num))
if __name__ == "__main__":
main()
利用g_num 将数据传递给两个子线程分别进行修改。
五:多线程存在的问题:
两个线程:一个线程写文件,另一个也写文件,就会产生资源竞争。上个案例一个写,一个读所以不会出现资源竞争。
解释:对于同样一个全局变量,当第一个线程拿到获取获取到g_num(0),并且加一后还没有重新赋值给g_num的时候,操作系统由于时间到了,便让这个线程阻塞,让另外一个线程继续执行,而这个线程重新取到的数据还是(0),此时让他全部执行完,g_num变成了(1),当第二个线程全部执行完后,第一个线程由阻塞状态变成执行状态,此时第一个线程又把1赋值给了g_num。这样结果就导致,两个线程分别加一次,但是最后结果却只增加1。这就是资源竞争。