当前位置: 首页 > 后端技术 > Python

这是不可能的,更何况你是在玩编程

时间:2023-03-25 20:44:45 Python

线程概述多线程类似于同时执行多个不同的程序。多线程有以下优点:使用线程可以将任务放在需要长时间在后台处理的程序中。用户界面可以更具吸引力。例如,当用户点击某个按钮触发某些事件的处理时,可以弹出一个进度条来显示处理的进度。程序的运行速度可能会加快。一些等待任务如用户输入、文件Threads对于通过网络读写和发送和接收数据更有用。在这种情况下我们可以释放一些宝贵的资源,比如内存占用等等。线程和进程在执行过程中还是有区别的。每个独立的进程都有程序执行的入口点、顺序执行顺序和程序的出口点。但是线程不能独立执行,必须依赖于应用程序,应用程序提供多线程执行控制。每个线程都有自己的一组CPU寄存器,称为线程的上下文,它反映了线程上次运行该线程时CPU寄存器的状态。指令指针和堆栈指针寄存器是线程上下文中最重要的两个寄存器。线程总是在进程的上下文中运行。这些地址用于标记拥有该线程的进程地址空间中的内存。线程可以被抢占(中断)。当其他线程正在运行时,线程可以暂时搁置(也称为休眠)——这就是线程让步。线程是程序运行过程中执行程序代码的一个分支。每个运行的程序至少有一个线程,创建多线程:thread调用thread模块中的start_new_thread()函数生成一个新的线程thread.start_new_thread(function,args[,kwargs])function——线程函数。args-传递给线程函数的参数,它必须是元组类型。kwargs-可选参数。启动python多线程start()importthreadingimporttimedeftask():time.sleep(1)print("当前线程:",threading.current_thread().name)if__name__=='__main__':for_inrange(5):sub_thread=threading.Thread(target=task)sub_thread.start()线程间执行乱序。主线程会等待所有子线程结束后才结束。主线程会等待所有子线程结束后才结束。如果需要,可以设置守护主线程的多线程特性(共享全局变量)threading.currentThread():返回当前线程变量。threading.enumerate():返回正在运行的线程列表。运行是指线程启动后结束前,不包括启动前和终止后的线程。threading.activeCount():返回正在运行的线程数,与len(threading.enumerate())的结果相同。线程模块除了使用方法外,还提供了Thread类来处理线程。Thread类提供了以下方法:run():一种用于表示线程活动的方法。start():启动线程活动。join([time]):等到线程终止。这会阻塞调用线程,直到调用线程的join()方法以中止-正常退出或抛出未处理的异常-或者发生可选的超时。isAlive():返回线程是否存活。getName():返回线程名称。setName():设置线程名称。自定义线程自定义线程不能指定目标,因为自定义线程中的任务都是在run方法中执行的。启动线程统一调用start方法。不要直接调用run方法,因为这不是使用子线程来执行任务。importthreading#自己定义线程类classMyThread(threading.Thread):#通过构造方法获取接收任务的参数def__init__(self,info1,info2):#调用父类的构造方法super(MyThread,self).__init__()self.info1=info1self.info2=info2#定义自定义线程相关任务deftest1(self):print(self.info1)deftest2(self):print(self.info2)#通过执行相关任务run方法defrun(self):self.test1()self.test2()创建自定义线程my_thread=MyThread("Test1","Test2")启动my_thread.start()资源竞争问题多线程可以共享全局变量多线程可以共享全局变量,非常方便多线程之间共享数据因为多个线程同时操作全局变量,容易造成资源竞争。importthreading#定义全局变量g_num=0#循环一次将1defsum_num1()添加到全局变量:foriinrange(1000000):globalg_numg_num+=1print("sum1:",g_num)#循环一次将1添加到全局变量defsum_num2():foriinrange(1000000):globalg_numnumg_num+=1__print("gname__)=='__main__':#创建两个线程first_thread=threading.Thread(target=sum_num1)second_thread=threading.Thread(target=sum_num2)#启动线程first_thread.start()#启动线程second_thread.start()我们可以看到多线程同时操作全局变量,出现错误多线程同时操作global时分析变量可能导致数据错误的原因。first_thread和second_thread这两个线程都需要给全局变量g_num加1(默认为0)。但是,由于多个线程同时运行,可能会出现以下情况:当g_num=0时,first_thread获取到g_num=0,此时系统将first_thread调度为“休眠”状态,将second_thread转换为“运行”状态,t2也得到g_num=0,然后second_thread将得到的值加1赋值给g_num,这样g_num=1,那么系统调度second_thread为“休眠”,first_thread为“运行”。线程t1将之前得到的0加1赋值给g_num。结果,虽然first_thread和first_thread都对g_num加1,但是结果还是g_num=1配速,按预定顺序跑。举个例子:你说完了我再说一遍,就像现实生活中对讲机的多个线程同时操作同一个全局变量一样,可能会出现资源竞争和数据错误的问题。线程同步可以解决资源竞争和数据出错的问题,但是这样一来多任务就变成了单任务。Lock变量在互斥锁线程模块中定义。这个变量本质上是一个可以方便处理锁的函数:createlockmutex=threading.Lock()lockmutex.acquire()releasemutex.release()importthreading#definitionGlobalvariableg_num=0#createaglobalmutexlock=threading.Lock()#循环一次将1def加到全局变量sum_num1():#Locklock.acquire()foriinrange(1000000):globalg_numg_num+=1print("sum1:",g_num)#release锁lock.release()#循环一次将1def添加到全局变量sum_num2():#locklock.acquire()foriinrange(1000000):globalg_numg_num+=1print("sum2:",g_num)#释放锁lock.release()if__name__=='__main__':#创建两个线程first_thread=threading.Thread(target=sum_num1)second_thread=threading.Thread(target=sum_num2)#启动线程first_thread.start()second_thread.start()提示:有了互斥锁,我们无法决定哪个线程抢到了锁,哪个线程抢到了锁,哪个线程先执行,哪个线程不抢到锁needstowait#加互斥锁多任务瞬间变成单任务,性能会下降,也就是说同一时间只能有一个线程执行。当线程调用锁的acquire()方法获取锁时,锁进入“锁定”状态。一次只有一个线程可以获取锁。如果此时另一个线程试图获取锁,则该线程将变为“阻塞”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁,并且锁进入“解锁”状态。线程调度器选择其中一个处于同步阻塞状态的线程获取锁,并使该线程进入运行状态。它保证了某一段关键代码从头到尾只能被一个线程完整执行。锁的缺点:多线程执行变成了某段包含锁的代码实际上只能在单线程模式下执行,效率大大降低。如果使用不当很容易出现死锁。deadlockimportthreadingimporttime#创建互斥锁lock=threading.Lock()#根据下标获取值,保证同一时刻只有一个线程可以获取到值defget_value(index):#Locklock.acquire()print(threading.current_thread())my_list=[3,6,8,1]#判断下标越界ifindex>=len(my_list):print("下标越界:",index)returnvalue=my_list[index]print(value)time.sleep(0.2)#释放锁lock.release()if__name__=='__main__':#模拟大量线程对iinrange(30)进行value操作:sub_thread=threading.Thread(target=get_value,args=(i,))sub_thread.start()使用互斥量时需要注意死锁问题,注意在合适的地方释放锁。一旦死锁发生,就会导致应用程序停止响应。线程优先级队列(Queue)Python的Queue模块提供了同步和线程安全的队列类,包括FIFO(先进先出)队列Queue、LIFO(后进先出)队列LifoQueue,以及优先级队列PriorityQueue.这些队列实现了锁原语,可以直接在多线程中使用。队列可以用来实现线程间的同步。Queue模块中的常用方法:Queue.qsize()返回队列的大小Queue.empty()如果队列为空返回True,否则FalseQueue.full()如果队列满则返回True,否则返回FalseQueue.full和maxsize对应Queue.get([block[,timeout]])获取队列,超时等待时间Queue.get_nowait()相当于Queue.get(False)Queue.put(item)写队列,超时等待时间Queue.put_nowait(item)Queue.put(item,False)Queue.task_done()完成一个作业后,Queue.task_done()函数向队列发送一个信号,表示任务已经完成Queue.join()实际上是等待直到队列为空,再执行其他操作线程,你学会浪费了吗?