在这里首先上两段代码了解一下使用多线程和不使用多线程的区别,从而了解多线程的用处
一,
1,不使用多线程
import time
#未使用多线程,运行该程序需大概6秒
def speaking_demo():
for x in range(3):
print("我在说话 %s" % x)
time.sleep(1)#停止一秒
def writing_demo():
for x in range(3):
print("我在写字 %s" % x)
time.sleep(1)#停止一秒
def main():
speaking_demo()
writing_demo()
if __name__ == '__main__':
main()
这是一个非常普通的代码段,轮流执行speaking和writing,每次执行完都沉睡一秒,执行时间极短,我们忽略,运行完整个代码段大概6秒
2,使用多线程
import threading
import time
#使用线程,两个函数会几乎同时运行,时间约3秒
def speaking_demo():
for x in range(3):
print("我在说话 %s" % x)
time.sleep(1)#停止一秒
def writing_demo():
for x in range(3):
print("我在写字 %s" % x)
time.sleep(1)#停止一秒
def main():
t_1 = threading.Thread(target=speaking_demo) #创建线程1,传值时传入函数名,不加括号
t_2 = threading.Thread(target=writing_demo) #创建线程2,
t_1.start()#开始线程1
t_2.start()#开始线程2
if __name__ == '__main__':
main()
我们使用了多线程来执行这两个函数,当进程把执行speaking任务给到线程1的时候,它不会等线程1执行完再去把writing任务给线程2执行,而是几乎在把speaking任务给线程1的同时,把writing任务给线程2,所以speaking和writing任务几乎是同时执行,所以,运行这个代码段大概需要3秒。
那么,上面的写法是不规范的,我们了解一下规范的写法,让它继承自父类
import threading
import time
class Speaking_demo(threading.Thread):
def run(self):#重写run方法
for x in range(3):
print("我在说话 %s " % threading.current_thread())#该方法查看线程名
time.sleep(1)
class Writing_demo(threading.Thread):
def run(self):
for x in range(3):
print("我在写字 %s " % threading.current_thread())
time.sleep(1)
def main():
t1 = Speaking_demo()
t2 = Writing_demo()
t1.start()
t2.start()
print(threading.enumerate())#该方法查看线程数
if __name__ == '__main__':
main()
那么,在代码中,也注释了几种常用方法。不在一一赘述。
二,我们来了解一下全局问题与锁机制
首先,我们看一个例子,在这个例子中,我们不使用锁
import threading
value = 0
#创建test方法,该方法使全局变量+1 ,当值足够大时,未使用锁机制,线程会混乱导致程序出错
def test():
global value #调用全局变量
for x in range(100):
value += 1
print(value)
def main():
for x in range(2):
t1 = threading.Thread(target=test)
t2 = threading.Thread(target=test)
t1.start()
t2.start()
#
if __name__ == '__main__':
main()
我们给了一个test方法,使全局变量+1,当我们循环100次,并使用两个线程时,第一个线程会把它加到100,第二个会把它加到200,我们看看结果
我们再试试更大的数,1000000
明显结果是错的。
我们使用锁机制在试试
import threading
value = 0
gLock = threading.Lock()
def test():
global value #调用全局变量
gLock.acquire()#加锁
for x in range(1000000):
value += 1
gLock.release()#释放锁
print(value)
# #创建main方法,用test方法建立两个线程
def main():
for x in range(2):
t1 = threading.Thread(target=test)
t2 = threading.Thread(target=test)
t1.start()
t2.start()
#
if __name__ == '__main__':
main()
我们得到了正确的结果,锁机制,会在一个线程调用并需要改变全局变量时,阻止其他线程调用改变该全局变量,避免引起混乱,加锁之后一定要释放锁。
另外,如果我们只是调用查看全局变量,则不需要锁机制,在改变全局变量时,一定要加锁。
三:我们简单了解一下安全队列:
from queue import Queue
q = Queue(4) #定义一个安全队列,容量4
for x in range(4):
q.put(x) #put方法把元素放入队列
print(q.full())#full 方法判断队列是否满
for x in range(4):
q.get() #get方法获取队列值,并将该值从队列中移除
print(q.empty()) #empty 方法判断队列是否空
上面给了安全队列的几种常用方法。
后续我们实战会用到。