Python之线程

    技术2022-07-11  108

    Python之线程

    1.线程简介(1)线程概念(2)线程与进程 2.线程的格式(1)格式(2)主要参数(3)常用方法 3.线程的创建示例(1)不设置线程名、被调函数不需要传参(2)设置线程名、被调函数需要传参(3)不写 join()方法(4)守护线程 4.锁线程实例(1)不加锁(2)加锁

    1.线程简介

    (1)线程概念

    线程是指进程内的一个执行单元,也是进程内的可调度实体;相当于是进程的一个子任务是操作系统能够进行运算调度的最小单位

    (2)线程与进程

    一个程序中至少有一个进程,而一个进程中也至少有一个线程

    2.线程的格式

    (1)格式

    import threading #导入threading模块 threading.Thread(target=None, name=None, args=())

    (2)主要参数

    参数名作用target需要调用的函数名name设置线程的名字args被调用函数所需要的参数(以元组的形式传入)

    (3)常用方法

    方法名功能start()启动线程join()等待子线程结束setName()设置线程名getName()返回线程名setDaemon()设置守护线程

    3.线程的创建示例

    (1)不设置线程名、被调函数不需要传参

    import threading import time def task1(): print(threading.current_thread().name,2) #current_thread()方法能返回当前线程的对象;current_thread().name方法即能返回当前线程的名称;第个参数是为了区别线程名所做的标号 for i in range(1,6): time.sleep(2) print("*****我采摘%s个苹果"%i) def task2(): print(threading.current_thread().name, 3) for i in range(1,6): time.sleep(2) print("$$$$$我采摘%s个苹果"%i) print(threading.current_thread().name,0) print(time.ctime()) #创建线程 per1=threading.Thread(target=task1) per2=threading.Thread(target=task2) #启动线程 per1.start() per2.start() #等待线程结束 per1.join() per2.join() print(time.ctime()) print(threading.current_thread().name,1) MainThread 0 #主线程的默认名 Fri Jul 3 16:53:59 2020 Thread-1 2 #线程1的默认名 Thread-2 3 #线程2的默认名 *****我采摘1个苹果 $$$$$我采摘1个苹果 *****我采摘2个苹果 $$$$$我采摘2个苹果 *****我采摘3个苹果 $$$$$我采摘3个苹果 $$$$$我采摘4个苹果 *****我采摘4个苹果 $$$$$我采摘5个苹果 *****我采摘5个苹果 Fri Jul 3 16:54:09 2020 MainThread 1

    (2)设置线程名、被调函数需要传参

    被调函数参数需要以元组形式传入,否则会出错 import threading import time def task1(a): #task1函数需要传入参数a print(threading.current_thread().name,2,a) for i in range(1,6): time.sleep(2) print("*****我采摘%s个苹果"%i) def task2(): print(threading.current_thread().name, 3) for i in range(1,6): time.sleep(2) print("$$$$$我采摘%s个苹果"%i) print(threading.current_thread().name,0) print(time.ctime()) per1=threading.Thread(target=task1,name="线程1",args=(10,)) #通过name参数来设置线程名;通过args参数,设置被调用函数task1所需传入的参数(参数要以元组的形式传入,否则会出错) per2=threading.Thread(target=task2) #若传入的参数只有一个时,需要加逗号",",否则会被认为传入的参数是整数而不是元组 per2.setName("线程2") #通过setName方法来设置线程名 per1.start() per2.start() per1.join() per2.join() print(time.ctime()) print(threading.current_thread().name,1) MainThread 0 Fri Jul 3 17:58:03 2020 线程1 2 10 #通过name参数更改了线程名为线程1;10为通过args参数传入的被调函数所需参数 线程2 3 #通过setName方法更改了线程名线程2 *****我采摘1个苹果 $$$$$我采摘1个苹果 *****我采摘2个苹果 $$$$$我采摘2个苹果 *****我采摘3个苹果 $$$$$我采摘3个苹果 *****我采摘4个苹果 $$$$$我采摘4个苹果 *****我采摘5个苹果 $$$$$我采摘5个苹果 Fri Jul 3 17:58:13 2020 MainThread 1

    (3)不写 join()方法

    主线程不会等待子线程结束,当主线程执行完自己的任务就直接结束,而子线程继续执行自己的任务 import threading import time def task1(a): print(threading.current_thread().name,2,a) for i in range(1,6): time.sleep(2) print("*****我采摘%s个苹果"%i) def task2(): print(threading.current_thread().name, 3) for i in range(1,6): time.sleep(2) print("$$$$$我采摘%s个苹果"%i) print(threading.current_thread().name,0) print(time.ctime()) per1=threading.Thread(target=task1,name="线程1",args=(10,)) per2=threading.Thread(target=task2) per2.setName("线程2") per1.start() per2.start() print(time.ctime()) print(threading.current_thread().name,1) MainThread 0 Fri Jul 3 18:19:31 2020 线程1 2 10 线程2 3 Fri Jul 3 18:19:31 2020 MainThread 1 #主线程不会等待子线程结束,当主线程执行完自己的任务就直接结束 *****我采摘1个苹果 #子线程执行自己的任务 $$$$$我采摘1个苹果 *****我采摘2个苹果 $$$$$我采摘2个苹果 *****我采摘3个苹果 $$$$$我采摘3个苹果 $$$$$我采摘4个苹果 *****我采摘4个苹果 *****我采摘5个苹果 $$$$$我采摘5个苹果

    (4)守护线程

    守护线程就是主线程不管该线程的执行情况,只要其它子线程结束以及主线程执行结束,程序直接结束,守护线程也直接结束 import threading import time def task1(a): print(threading.current_thread().name,2,a) for i in range(1,6): time.sleep(2) print("*****我采摘%s个苹果"%i) def task2(): print(threading.current_thread().name, 3) for i in range(1,6): time.sleep(2) print("$$$$$我采摘%s个苹果"%i) print(threading.current_thread().name,0) print(time.ctime()) per1=threading.Thread(target=task1,name="线程1",args=(10,)) per2=threading.Thread(target=task2) per2.setName("线程2") #将两个子线程都设为守护线程 per1.setDaemon(True) per2.setDaemon(True) per1.start() per2.start() print(time.ctime()) print(threading.current_thread().name,1) MainThread 0 Sat Jul 4 13:02:58 2020 线程1 2 10 线程2Sat Jul 4 13:02:58 2020 MainThread 1 #执行完主线程就直接结束,不会等待两个守护线程结束

    4.锁线程实例

    (1)不加锁

    import threading blance = 0 def access(n): #存取函数,存入n,再取出n global blance blance = blance + n blance = blance - n def task(arg, n): while arg > 0: try: access(n) finally: arg = arg - 1 #创建线程 t1 = threading.Thread(target=task, args=(40000, 5)) #被调函数的第一个参数为操作次数,第二个参数为每次存取的钱数;t1任务:进行40000次的存5元,取5元 t2 = threading.Thread(target=task, args=(40000, 8)) #t2任务:进行40000次的存8元,取8元 t1.start() t2.start() t1.join() t2.join() print(blance) 多次运行后,得出的结果分别为:0,0,0,5,0,0,-8,0,5,5,0由上可知,若多个线程不加锁,就有可能多个线程同时修改某一个变量,会将数据改乱,得出的结果会与实际结果不同

    (2)加锁

    通过 threading.RLock() 方法来创建锁,之后通过 acquire() 方法来获取锁,release() 方法释放锁 import threading blance = 0 lock = threading.RLock() #通过threading.RLock()方法来建立一个锁;锁不能在存取函数中建立,否则就达不到锁的效果 def access(n): global blance blance = blance + n blance = blance - n def task(arg, n): while arg > 0: lock.acquire() #获得锁 try: access(n) finally: lock.release() #释放锁 arg = arg - 1 t1 = threading.Thread(target=task, args=(40000, 5)) #t1任务:进行40000次的存5元,取5元 t2 = threading.Thread(target=task, args=(40000, 8)) #t2任务:进行40000次的存8元,取8元 t1.start() t2.start() t1.join() t2.join() print(blance) 无论程序执行多少次,结果都是0,与实际结果相同
    Processed: 0.012, SQL: 10