threading 模块
两种方式:线程处理函数 与 继承 threading.Thread 类
使用线程处理函数创建多线程的用法类似于 thread 模块创建多线程
使用继承 threading.Thread 类实现多线程的本质就是重写 threading.Thread 类中的 构造函数 与 run 方法
# (1) 线程处理函数
# threading.Thread(target=run, args=("t1",)).start()
# run 线程处理函数
# args 线程处理函数的参数,元祖类型# (2) 继承thread类创建多线程
# class MyThread(threading.Thread):
# def __init__(self, params):
# pass
# def run(self):
# pass
# t1 = MyThread(params)
# t1.start()
import threading
import time# MyThread 类继承自 threading.Thread 类
# MyThread 类里面重写父类的构造函数和 run 函数
class MyThread(threading.Thread):def __init__(self, name, n):super(MyThread, self).__init__()self.name = nameself.n = ndef run(self):while True:print("Thread ", self.name, "is running")time.sleep(self.n)def main():t1 = MyThread("t1", 3)t2 = MyThread("t2", 2)t1.start()t2.start()if __name__ == "__main__":print()main()
import threading
import timedef handler_haicoder(val):while True:print("thread haicoder run, val =", val)time.sleep(2)def handler_python(val):while True:print("thread python run, val =", val)time.sleep(3)def main():threading.Thread(target=handler_haicoder, args=("haicoder",)).start()threading.Thread(target=handler_python, args=("python",)).start()if __name__ == '__main__':print()main()
_thread模块
def handler_demo1(val):while True:print("demo1 run, val =", val)time.sleep(2)def handler_demo2(val):while True:print("thread demo2 run, val =", val)time.sleep(3)# 派生一个新的线程,给定args和kwargs来执行function
# _thread.start_new_thread(function,args,kwargs=None)# 分配锁对象
# _thread.allocate_lock()# 线程退出
# _thread.exit()# 获取锁对象
# lock.acquire(waitflag=1, timeout=-1)# 如果获取了锁对象返回true,否则返回false
# lock.locked()# 释放锁
# lock.release()# 锁对象类型
# _thread.LockType()# 获取线程标识符
# _thread.get_ident()# _thread.TIMEOUT_MAX
# lock.acquire的最大时间,超时将引发OverflowError# 引发主线程KeyboardInterrupt错误,子线程可以用这个函数来终止主线程
# _thread.interrupt_main()def handler_haicoder(val):while True:print("thread haicoder run, val =", val)time.sleep(2)def handler_python(val):while True:print("thread python run, val =", val)time.sleep(3)def main():threading.Thread(target=handler_haicoder, args=("haicoder",)).start()threading.Thread(target=handler_python, args=("python",)).start()if __name__ == '__main__':main()time.sleep(10)
守护线程
import threading
import timeclass MyThread(threading.Thread):def __init__(self, name, n):super(MyThread, self).__init__()self.name = nameself.n = ndef run(self):while True:print("Thread ", self.name, "run")time.sleep(self.n)def main():t1 = MyThread("t1", 3)t1.setDaemon(True)t1.start()t2 = MyThread("t2", 2)t2.setDaemon(True)t2.start()# 在 Python 中,线程分为三种形式,即主线程、守护线程和非守护线程
# 主线程也叫 main 线程,主线程不是守护线程# 守护线程是指在程序运行时在后台提供一种通用服务的线程
# 非守护线程也叫用户线程,是由用户创建的线程# 主线程结束时,守护线程也会一起销毁
# 主线程的退出,对非守护线程没有任何影响,因为主线程和守护线程互不影响
# 在创建线程实例之后,调用线程实例的 setDaemon 函数,即可以将线程设置为守护线程
# setDaemon 函数必须在 start() 之前调用# 守护线程虽然有 while 循环,但因为主线程没有 sleep 等待,也没有被阻塞,因此运行后会立刻退出
# 主线程退出,守护线程也会自动退出if __name__ == "__main__":print()main()time.sleep(5)
主线程等待子线程结束和互斥锁
# 在主线程中开启多个子线程时,如果主线程没有 sleep 或没有阻塞
# 那么程序刚运行之后,主线程就立刻退出
# 期望当子线程没有运行完毕时,主线程不要退出,而是等待子线程运行完毕之后,主线程才退出
# 使用 join,让主线程等待子线程运行完毕后再退出# threading 模块提供了 Lock 和 RLock 两个类,即互斥锁和递归锁
# from threading import Thread,Lock
# 创建互斥锁
# lock = threading.Lock()
# # 对需要访问的资源加锁
# lock.acquire()
# 资源访问结束解锁
# lock.release()import threading
import timelock = threading.Lock()class MyThread(threading.Thread):def __init__(self, name, n):super(MyThread, self).__init__()self.name = nameself.n = ndef run(self):i = 0while i < 300:lock.acquire()print("Thread ", self.name, "is running")lock.release()time.sleep(self.n)i = i + 1def main():t1 = MyThread("t1", 3)t1.setDaemon(True)t1.start()t2 = MyThread("t2", 2)t2.setDaemon(True)t2.start()# join 函数接受一个 timeout 可选参数# 如果当前线程运行时间未超过 timeout,那么就一直等待线程结束# 如果当前线程运行时间已经超过 timeout,那么主线程就不再继续等待# timeout 参数如果不传递,则是永久等待,直到子线程退出t1.join(10)t2.join(10)if __name__ == "__main__":print()main()
嵌套锁
# RLock 内部维护着一个 Lock 和一个 counter 变量
# counter 记录了 acquire 的次数,从而使得资源可以被多次 acquire
# 直到一个线程所有的 acquire 都被 release,其他的线程才能获得资源# from threading import Thread
# 创建递归锁
# lock = threading.RLock()
# 对需要访问的资源加锁
# lock.acquire()
# lock.acquire()
# 资源访问结束解锁
# lock.release()
# lock.release()import threadingnum = 0
# 创建递归锁
lock = threading.RLock()def handler_incry():global numlock.acquire()lock.acquire()for i in range(100000):num += 1print("handler_incry done, num =", num)lock.release()lock.release()def handler_decry():global numlock.acquire()lock.acquire()for i in range(100000):num -= 1print("handler_decry done, num =", num)lock.release()lock.release()if __name__ == '__main__':print()# 创建线程t1 = threading.Thread(target=handler_incry)t2 = threading.Thread(target=handler_decry)# 启动线程t1.start()t2.start()t1.join()t2.join()
信号量
# 信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用
# 信号量是多把锁,同时允许多个线程来更改数据,而 互斥锁 同时只允许一个 线程 更改数据
# 信号量的一个特殊用法是互斥量。互斥量是初始值为 1 的信号量,可以实现数据、资源的互斥访问# 语法
# import threading
# sem = threading.Semaphore(3)
# sem.acquire()
# sem.release()
# 需要使用 threading.Semaphore 创建一个信号量的实例
# 创建实例时,需要指定一个 value 参数 大小,表示内部维护的计数器的大小,默认为 1
# 在对临界资源进行访问时,调用 acquire(),此时内置计数器 -1,直到为 0 的时候就阻塞
# 资源调用完毕后调用 release(),内置计数器 +1,并让某个线程的 acquire() 从阻塞变为不阻塞import threading
import timesemaphore = threading.Semaphore(3) # 最多允许3个线程同时运行def run(n):semaphore.acquire()time.sleep(1)print("thread:%s is running" % n)semaphore.release()if __name__ == '__main__':print()for i in range(6):t = threading.Thread(target=run, args=(i,))t.start()
# while 循环 的作用相当于 join() 等待线程执行完毕
# 如果活跃数为1,则说明只有主线程,则表明线程全部运行结束
while threading.active_count() != 1:pass
else:print('----all threads done---')