线程和多线程
1.线程的实现
1.1.简介
在python中实现线程主要用到了两个模块,一个是_thread,另一个是threading,threading是对_thread模块进行了封装,所以实际情况我们一般都是用threading。
1.2.常用说明
1.target (表示要调用的子线程的对象)
2.name (线程的名字)
3.args (为位置参数,为元祖,特别注意当只有一个数的时候一定要在最后面加上,)
from threading import Thread # threading 是Thread模块下的一个类,所以要用from调用
import time
def f1(person): # 将要调用的子线程
print("hello,{}".format(person))
time.sleep(3)
print("bye")
def f2(person):
print("heihei,{}".format(person))
time.sleep(3)
print("godbye")
if __name__ == '__main__':
f1_thread = Thread(target=f1, args=("thomas",))
f2_thread = Thread(target=f2, args=("xiaohei",))
f1_thread.start() # 通过start来调用子线程
f2_thread.start()
f1_thread.join() # 通过join来阻塞主线程,等子线程做完才能继续继续主线程
f2_thread.join()
print("主线程调用")
这是结果,我们知道,我们将子线程都睡了三秒,但是最后打印的依旧是主线程调用,所以可以看出join的作用所在。
这里还有一些实例用法
这个就是主要演示的是name方法,主要有两个,一个是setname,一个是getname,方法演示如图片所示
这是守护线程,通过守护线程来做到当主线程结束就全部结束了,就是接着往下跑,不等子线程了
1.3 Thread类的继承和改写
其实这里还有一个方法就是run方法,接下来通过一个类的改写来更加清楚的了解这个run方法是如何实现功能的。
from threading import Thread
import time
class My_Thread(Thread):
def run(self):
print("hello")
time.sleep(3)
print("bye")
if __name__ == '__main__':
my_thread = My_Thread()
my_thread.start()
这里就是通过类的继承改写原来的run方法,我们可以看到start是调用run方法。
这是代码及运行结果。
from threading import Thread
import time
class My_Thread(Thread):
def __init__(self, people, *args, **kwargs):
super().__init__(*args,**kwargs)
self.people = people
def run(self):
print("hello,{}".format(self.people))
time.sleep(3)
print("bye")
if __name__ == '__main__':
my_thread = My_Thread("thomas", name="lalal")
print(my_thread.getName())
my_thread.start()
如果你想改写这个类使用更灵活一点的话,在__init__这里一定要super().__init__这样的话才能继承原来的功能块中的功能,不然的话原来的功能就会被改写,而且会报错,这里一定要加上,*args,和**kwargs,这两个是动态数组,前面是元祖和列表,后面对应字典。
这是代码总览。
这是结果。
2.互斥锁
from threading import Thread,Lock
data = 0
def f1():
global data
for i in range(10000):
data+= 1
def f2():
global data
for i in range(10000):
data-= 1
if __name__ == '__main__':
lock = Lock()
t1 = Thread(target=f1())
t2 = Thread(target=f2())
t1.start()
t2.start()
t1.join()
t2.join()
print(data)
这里面是全局变量,多个线程的话一起修改全局变量,可能会打架,所以就有了互斥锁,这个操作系统里也讲过,如果不加这个锁的话,结果是未知的。
这里就是演示的结果了。
3.队列
# -*- coding: utf-8 -*-
from threading import Thread
from queue import Queue
from random import randint
my_queue = Queue(10)
def my_put(my_queue):
for x in range(10):
num = randint(0,1000)
my_queue.put(num)
def my_get(my_queue):
for y in range(3):
num = my_queue.get()
print(num)
if __name__ == '__main__':
p = Thread(target=my_put, args=(my_queue,))
g = Thread(target=my_get, args=(my_queue,))
p.start()
g.start()
p.join()
g.join()
这里就是演示一下关于队列的用法。这也是一种不打架的方式,队列就是数据结构中的一种数据类型。
接下来就是介绍一下队列的一些操作,其中主要包括task,这个是用来关闭put的,他们是一一对应的,有几个put就有几个task。
from queue import Queue
my_queue = Queue(3)
if __name__ == '__main__':
my_queue.put(1)
print(my_queue.qsize()) # 当前队列长度,1
my_queue.get()
print(my_queue.qsize()) # 当前队列长度,0
my_queue.put(1)
my_queue.put(1)
my_queue.put(1)
my_queue.task_done()
my_queue.task_done()
my_queue.task_done()
my_queue.task_done()
print(my_queue.full()) # 判断当前是否为满状态
my_queue.join() # 这个和之前是一样的,用来让主线程等待一下,用来判断task和put是否对等
print("主线程已经结束了")
这个就是大致的演示结果,你不信的话可以试一试,如果没有task,你设置一下join,你发现进程是结束不了的。
(未完待续,还有一个线程池没写)