线程是操作系统直接支持的执行单元
线程:运行是没有先后顺序的
同时运行的理解:
实际上是多个线程之间轮流执行的,就是将一个时间段分成若干个时间片,每个线程只运行一个时间片,由于时间片极短,而且电脑运行极快,线程之间切换也极快,几乎可以看做是并行运行的,也就是说可以看成是同时运行的.但实际却不是的同时运行的.
- 线程的实现
python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便地被使用
import time
import threading
def sing():
for i in range(5):
print("正在唱111")
time.sleep(1)
def dance():
for i in range(10):
print("正在跳222")
time.sleep(1)
def main():
t1=threading.Thread(target=sing)
t2=threading.Thread(target=dance)
t1.start()
t2.start()
while True:
print(len(threading.enumerate()))
if len(threading.enumerate())<=1:
break
time.sleep(1)
if __name__=="__main__":
main()
使用Thread类完成创建线程(必须要用run方法)
import time
import threading
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
print("hello")
self.p()
def p(self):
print("hi")
def main():
t= MyThread()
t.start()#创建一个实例对象只能创建一个线程可以在run里面调用这个类的其他方法
if __name__=="__main__":
main()
在方法中传入参数
threading.Thread(target=text,args=(XXX,)
第二个参数args是一个元组,如果只传递一个值,就只需要i, 如果需要传递多个参数,那么还可以继续传递下去其他的参数。特别注意其中的逗号不能少,少了就不是元组了,就会报错
import time
import threading
g_num=0
def text(num):
global g_num
for i in range(num):
g_num+=1
print("text1=%d"%g_num)
def text2(num):
global g_num
for i in range(num):
g_num+=1
print("text2=%d"%g_num)
def main():
t1=threading.Thread(target=text,args=(100,))
t2 =threading.Thread(target=text2,args=(100,))
t1.start()
t2.start()
time.sleep(1)
print("g_num=%d"%g_num)
if __name__=="__main__":
main()
- 同步与互斥
同步:按照预定的先后次序进行执行 先A后B
互斥锁:保证每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性
创建互斥锁 每一个线程在开始和结束都要进行锁定和释放两个操作
#创建锁
mutex=threading.Lock()#默认是没有上锁
#锁定
mutex.acquire()
#释放
mutex.release()
给资源加锁, 而是用锁去锁定资源,你可以定义多个锁, 像下面的代码, 当你需要独占某一资源时,任何一个锁都可以锁这个资源
with 后面有两个必须执行的操作:__enter__ 和 _exit__
不管里面的操作结果如何,都会执行打开、关闭
打开锁、处理内容、释放锁
with self.lock:
do
- Join
知识点一:
当一个进程启动之后,会默认产生一个主线程,因为线程是程序执行流的最小单元,当设置多线程时,主线程会创建多个子线程,在python中,默认情况下(其实就是setDaemon(False)),主线程执行完自己的任务以后,就退出了,此时子线程会继续执行自己的任务,直到自己的任务结束,例子见下面一。
知识点二:
当我们使用setDaemon(True)方法,设置子线程为守护线程时,主线程一旦执行结束,则全部线程全部被终止执行,可能出现的情况就是,子线程的任务还没有完全执行结束,就被迫停止,例子见下面二。
知识点三:
此时join的作用就凸显出来了,join所完成的工作就是线程同步,即主线程任务结束之后,进入阻塞状态,一直等待其他的子线程执行结束之后,主线程在终止,例子见下面三。
知识点四:
join有一个timeout参数:
当设置守护线程时,含义是主线程对于子线程等待timeout的时间将会杀死该子线程,最后退出程序。所以说,如果有10个子线程,全部的等待时间就是每个timeout的累加和。简单的来说,就是给每个子线程一个timeout的时间,让他去执行,时间一到,不管任务有没有完成,直接杀死。
没有设置守护线程时,主线程将会等待timeout的累加和这样的一段时间,时间一到,主线程结束,但是并没有杀死子线程,子线程依然可以继续执行,直到子线程全部结束,程序退出。
线程也要都在主线程之前执行完毕
for thread in treadcawl:#threadcrawl里面是线程集合
thread.join()