python异常机制、多进程与PyQt5中的QTimer、多线程

阳光穿透心脏的1/2处 2022-03-31 08:36 915阅读 0赞

1.异常处理机制

  1. def test(x):
  2. try:
  3. y = 10 / x
  4. print(y)
  5. #except Exception as e:
  6. #print(e) #可以打印出异常的类型
  7. except ZeroDivisionError: #抛出异常,执行下面的程序,如果是界面软件可以弹出一个窗口,提示用户输入错误
  8. print(x)
  9. else: #如果程序不存在异常,则执行该程序
  10. print(100 / x)
  11. finally:
  12. print('the program end') #不管程序是否错误,始终都会执行
  13. test(0)
  14. # 0
  15. # the program end
  16. test(1)
  17. # 10.0
  18. # 100.0
  19. # the program end
  20. def test2():
  21. try:
  22. assert False, 'error'
  23. except:
  24. print('another')
  25. # 输出 another
  26. def myLevel(level):
  27. if level < 1:
  28. raise ValueError('Invalid level', level) #自定义异常
  29. try:
  30. myLevel(0)
  31. except ValueError:
  32. print('level < 1')
  33. #输出 :level < 1
  34. print('test 2--')
  35. test2()

2.多进程

引入多进程的库文件: import multiprocessing

多进程测试, 需要在主函数 main 中 进行测试
创建进程的类:Process([group [, target [, name [, args [, kwargs]]]]]),target表示调用对象,args表示调用对象的位置参数元组。kwargs表示调用对象的字典。name为别名。group实质上不使用。
方法:is_alive()、join([timeout])、run()、start()、terminate()。其中,Process以start()启动某个进程。
属性:authkey、daemon(要通过start()设置)、exitcode(进程在运行时为None、如果为–N,表示被信号N结束)、name、pid。其中daemon是父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置

daemon 是守护进程 :daemon是父进程终止后自动终止,且自己不能产生新进程,必须在start()之前设置。#主线程执行完毕之后,不管子线程是否执行完毕都随着主线程一起结束。

  1. def worker_1():
  2. print('this is worker 1')
  3. time.sleep(3)
  4. print('worker 1 end')
  5. # n = 3
  6. # while n > 0:
  7. # print("The time is {0}".format(time.ctime()))
  8. # time.sleep(interval)
  9. # n -= 1
  10. def worker_2():
  11. print('this is worker 2')
  12. time.sleep(3)
  13. print('worker 2 end')
  14. def worker_3():
  15. print('this is worker 3')
  16. time.sleep(3)
  17. print('worker 3 end')
  18. if __name__ == "__main__":
  19. p1 = multiprocessing.Process(target = worker_1, args = ())
  20. p2 = multiprocessing.Process(target = worker_2, args = ())
  21. p3 = multiprocessing.Process(target = worker_3, args = ())
  22. # p1.daemon = True # 设置子程序为 守护进程, 主程序结束后,它就随之结束(即如果没有join函数,将不执行worker1函数), 需要放在start 前面
  23. p1.start() #进程调用 start 的时候,将自动调用 run 函数
  24. p2.start()
  25. p3.start() #运行3 个worker 程序花费的时间为3 s, 使用了3 个进程进行处理
  26. p1.join()
  27. p2.join()
  28. p3.join() #添加 join 函数, 先执行 worker 函数, 再执行主进程函数
  29. for p in multiprocessing.active_children(): #这是主进程函数
  30. print('name is :' + p.name + 'pid is :' + str(p.pid) + 'is _alive: '+ str(p.is_alive()))
  31. print('电脑的核数'+ str(multiprocessing.cpu_count())) # 电脑的核数4
  32. print('end----')

输出:

  1. #---没有 join 函数---
  2. # name is :Process-1pid is :6488is _alive: True
  3. # name is :Process-2pid is :5660is _alive: True
  4. # name is :Process-3pid is :7776is _alive: True
  5. # 电脑的核数4
  6. # end----
  7. # this is worker 1
  8. # this is worker 2
  9. # this is worker 3
  10. # worker 1 end
  11. # worker 2 end
  12. # worker 3 end
  13. #---有 join 函数--- 等待所有子进程结束,再执行主进程
  14. # this is worker 1
  15. # this is worker 2
  16. # this is worker 3
  17. # worker 1 end
  18. # worker 2 end
  19. # worker 3 end
  20. # 电脑的核数4 #此时执行完线程, active_children() 为空
  21. # end----

使用多个进程访问共享资源的时候,需要使用Lock 来避免访问的冲突

  1. def worker_first(lock, f):
  2. with lock:
  3. with open(f, 'a+') as t: #with 自动关闭文件
  4. n = 3
  5. while n > 0:
  6. t.write('first write ---')
  7. n -= 1
  8. def worker_second(lock, f):
  9. lock.acquire() #获取锁
  10. try:
  11. with open(f, 'a+') as t:
  12. n = 3
  13. while n > 0:
  14. t.write('second write ---')
  15. n -= 1
  16. finally:
  17. lock.release() #使用异常机制,保证最后释放锁
  18. def myProcess():
  19. lock = multiprocessing.Lock()
  20. f = r'D:\myfile1.txt'
  21. p1 = multiprocessing.Process(target=worker_first, args=(lock, f, ))
  22. p2 = multiprocessing.Process(target=worker_second, args=(lock, f, ))
  23. p1.start()
  24. p2.start()
  25. print('end -----------')
  26. if __name__ == '__main__':
  27. myProcess()

输出:

  1. first write ---first write ---first write ---second write ---second write ---second write ---

进程池

进程池 Pool
在利用Python进行系统管理的时候,特别是同时操作多个文件目录,或者远程控制多台主机,并行操作可以节约大量的时间。当被操作对象数目不大时,可以直接利用multiprocessing中的Process动态成生多个进程,十几个还好,但如果是上百个,上千个目标,手动的去限制进程数量却又太过繁琐,
此时可以发挥进程池的功效。Pool可以提供指定数量的进程,供用户调用,当有新的请求提交到pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到规定最大值,
那么该请求就会等待,直到池中有进程结束,才会创建新的进程来它。

apply_async(func[, args[, kwds[, callback]]]) 它是非阻塞,apply(func[, args[, kwds]])是阻塞的

非阻塞和阻塞进程池

单个函数使用线程池:

  1. def func(msg):
  2. print('msg is :' + msg)
  3. time.sleep(2)
  4. print(msg + ' end')
  5. return msg + ' re'
  6. if __name__ == '__main__':
  7. pool = multiprocessing.Pool(processes=3) #创建进程池
  8. result = []
  9. for i in range(4):
  10. msg = '%d'%(i)
  11. # result.append(pool.apply_async(func, (msg, )))
  12. pool.apply_async(func, (msg, )) #非阻塞进程池, 维持总的进程数为 processes=3, 当一个进程结束后,添加另一个进程进去
  13. # pool.apply(func, (msg, )) #阻塞进程池
  14. print('start------')
  15. pool.close() # close 函数需要在 join 函数之前, 关闭进程池后,没有进程加入到pool中
  16. pool.join() # join函数等待所有子进程结束
  17. print('all program done')
  18. # print([re.get() for re in result]) #获取结果

输出:

  1. #---非阻塞进程池 输出------
  2. # start------
  3. # msg is :0
  4. # msg is :1
  5. # msg is :2
  6. # 0 end
  7. # msg is :3
  8. # 1 end
  9. # 2 end
  10. # 3 end
  11. # all program done
  12. #---阻塞进程池 输出------ 顺序执行
  13. # msg is :0
  14. # 0 end
  15. # msg is :1
  16. # 1 end
  17. # msg is :2
  18. # 2 end
  19. # msg is :3
  20. # 3 end
  21. # start------
  22. # all program done

多个函数使用线程池

  1. def f1():
  2. result = 0
  3. print('this is one')
  4. for i in range(100000):
  5. result += i
  6. return result
  7. def f2():
  8. result = 1
  9. print('this is two')
  10. for i in range(2, 100000):
  11. result *= i
  12. return result
  13. if __name__ == '__main__':
  14. start = time.time()
  15. myPool = multiprocessing.Pool(processes=2)
  16. result = []
  17. print('start----')
  18. myFunc = [f1, f2]
  19. for f in myFunc:
  20. result.append(myPool.apply_async(f)) #将输出结果保存到列表中
  21. myPool.close()
  22. myPool.join()
  23. print([re.get() for re in result])
  24. end = time.time()
  25. print('花费的时间: ' + str(end-start)) #huafei de 时间: 8.397480010986328
  26. print('end------')

使用get() 函数,同样可以获取pandas 的数据结构;

  1. def f1():
  2. result = 0
  3. print('this is one')
  4. result = pd.DataFrame(np.arange(16).reshape(-1, 4))
  5. return result
  6. # for i in range(100000):
  7. # result += i
  8. # return result
  9. def f2():
  10. result = 1
  11. print('this is two')
  12. result = pd.DataFrame(np.arange(9).reshape(-1, 3))
  13. return result
  14. # for i in range(2, 100000):
  15. # result *= i
  16. # return result
  17. if __name__ == '__main__':
  18. start = time.time()
  19. myPool = multiprocessing.Pool(processes=2)
  20. result = []
  21. print('start----')
  22. myFunc = [f1, f2]
  23. for f in myFunc:
  24. result.append(myPool.apply_async(f)) #将输出结果保存到列表中
  25. myPool.close()
  26. myPool.join()
  27. for re in result:
  28. print(re.get())

输出结果:

  1. start----
  2. this is one
  3. this is two
  4. 0 1 2 3
  5. 0 0 1 2 3
  6. 1 4 5 6 7
  7. 2 8 9 10 11
  8. 3 12 13 14 15
  9. 0 1 2
  10. 0 0 1 2
  11. 1 3 4 5
  12. 2 6 7 8
  13. 花费的时间: 0.9370532035827637
  14. end------

3.PyQt5 中的QTimer 模块

pyqt5中的多线程的应用,多线程技术涉及3种方法,1.使用计时器QTimer, 2.使用多线程模块QThread ,3.使用事件处理功能
1.使用QTimer模块,创建QTimer实例,将timeout信号连接到槽函数,并调用timeout 信号。 self.timer.start(1000)时间为毫秒
引入模块
from PyQt5.QtCore import QTimer, QDateTime

  1. def timerTest():
  2. class WinForm(QWidget):
  3. def __init__(self,parent=None):
  4. super(WinForm,self).__init__(parent)
  5. self.setWindowTitle("QTimer demo")
  6. self.listFile= QListWidget()
  7. self.label = QLabel('显示当前时间')
  8. self.startBtn = QPushButton('开始')
  9. self.endBtn = QPushButton('结束')
  10. layout = QGridLayout(self)
  11. # 初始化一个定时器
  12. self.timer = QTimer(self)
  13. # showTime()方法
  14. self.timer.timeout.connect(self.showTime) #
  15. layout.addWidget(self.label,0,0,1,2)
  16. layout.addWidget(self.startBtn,1,0)
  17. layout.addWidget(self.endBtn,1,1)
  18. self.startBtn.clicked.connect( self.startTimer) #首先按下start开始计时,到了2s后,触发timeout 信号
  19. self.endBtn.clicked.connect( self.endTimer)
  20. self.setLayout(layout)
  21. QTimer.singleShot(5000, self.showmsg) #给定的时间间隔后,调用一个槽函数来发射信号
  22. def showmsg(self):
  23. QMessageBox.information(self, '提示信息', '你好')
  24. def showTime(self):
  25. # 获取系统现在的时间
  26. time = QDateTime.currentDateTime() #获取当前时间
  27. # 设置系统时间显示格式
  28. timeDisplay = time.toString("yyyy-MM-dd hh:mm:ss dddd")
  29. # 在标签上显示时间
  30. self.label.setText( timeDisplay )
  31. def startTimer(self):
  32. # 设置计时间隔并启动
  33. self.timer.start(1000) #时间为 1 s
  34. self.startBtn.setEnabled(False)
  35. self.endBtn.setEnabled(True)
  36. def endTimer(self):
  37. self.timer.stop()
  38. self.startBtn.setEnabled(True) #依次循环
  39. self.endBtn.setEnabled(False)
  40. if __name__ == "__main__":
  41. app = QApplication(sys.argv)
  42. form = WinForm()
  43. form.show()
  44. # QTimer.singleShot(5000, app.quit) #界面运行5秒后,自动关闭
  45. sys.exit(app.exec_())
  46. timerTest()

20190103113137922.PNG

QThread模块,使用该模块开始一个线程,可以创建它的一个子类,然后覆盖QThread.run() 的方法。调用自定义的线程时,调用start()方法,会自动调用run的方法,
QThread 还有 started , finished 信号,可以见信号连接到槽函数中

  1. def threadTest():
  2. class MainWidget(QWidget):
  3. def __init__(self,parent=None):
  4. super(MainWidget,self).__init__(parent)
  5. self.setWindowTitle("QThread 例子")
  6. self.thread = Worker() #创建线程
  7. self.listFile = QListWidget()
  8. self.btnStart = QPushButton('开始')
  9. self.btnStop = QPushButton('结束')
  10. layout = QGridLayout(self)
  11. layout.addWidget(self.listFile,0,0,1,2)
  12. layout.addWidget(self.btnStart,1,1)
  13. layout.addWidget(self.btnStop,2,1)
  14. self.btnStart.clicked.connect( self.slotStart ) #通过按钮状态实现 线程的开启
  15. self.btnStop.clicked.connect(self.slotStop)
  16. self.thread.sinOut.connect(self.slotAdd)
  17. def slotStop(self):
  18. self.btnStart.setEnabled(True)
  19. self.thread.wait(2000)
  20. def slotAdd(self,file_inf):
  21. self.listFile.addItem(file_inf) #增加子项
  22. def slotStart(self):
  23. self.btnStart.setEnabled(False)
  24. self.thread.start() #线程开始
  25. #创建一个线程
  26. class Worker(QThread):
  27. sinOut = pyqtSignal(str) #自定义一个信号
  28. def __init__(self, parent=None):
  29. super(Worker, self).__init__(parent)
  30. self.work = True
  31. self.num = 0
  32. def run(self):
  33. while self.work == True:
  34. listStr = 'this is index file {0}'.format(self.num)
  35. self.sinOut.emit(listStr) #发射一个信号
  36. self.num += 1
  37. self.sleep(2) #休眠2 秒
  38. def __del__(self):
  39. self.work = False
  40. self.wait()
  41. if __name__ == "__main__":
  42. app = QApplication(sys.argv)
  43. demo = MainWidget()
  44. demo.show()
  45. sys.exit(app.exec_())
  46. # threadTest()

demo 2:

  1. def threadTest2():
  2. global sec
  3. sec=0
  4. class WorkThread(QThread): #自定义一个线程
  5. trigger = pyqtSignal()
  6. def __int__(self):
  7. super(WorkThread,self).__init__()
  8. def run(self):
  9. for i in range(2000000000):
  10. print('haha ' + str(i)) #此处放运行 量较大的程序
  11. # 循环完毕后发出信号
  12. self.trigger.emit()
  13. def countTime():
  14. global sec
  15. sec += 1
  16. # LED显示数字+1
  17. lcdNumber.display(sec)
  18. def work():
  19. # 计时器每秒计数
  20. timer.start(1000) #每秒运行完后,是lcd增加数字
  21. # 计时开始
  22. workThread.start()
  23. # 当获得循环完毕的信号时,停止计数
  24. workThread.trigger.connect(timeStop)
  25. def timeStop():
  26. timer.stop()
  27. print("运行结束用时",lcdNumber.value())
  28. global sec
  29. sec=0
  30. if __name__ == "__main__":
  31. app = QApplication(sys.argv)
  32. top = QWidget()
  33. top.resize(300,120)
  34. # 垂直布局类QVBoxLayout
  35. layout = QVBoxLayout(top)
  36. # 加个显示屏
  37. lcdNumber = QLCDNumber()
  38. layout.addWidget(lcdNumber)
  39. button = QPushButton("测试")
  40. layout.addWidget(button)
  41. timer = QTimer()
  42. workThread = WorkThread()
  43. button.clicked.connect(work)
  44. # 每次计时结束,触发 countTime
  45. timer.timeout.connect(countTime)
  46. top.show()
  47. sys.exit(app.exec_())
  48. threadTest2()

项目推荐:

2000多G的计算机各行业电子资源分享(持续更新)

2020年微信小程序全栈项目之喵喵交友【附课件和源码】

Spring Boot开发小而美的个人博客【附课件和源码】

Java微服务实战296集大型视频-谷粒商城【附代码和课件】

Java开发微服务畅购商城实战【全357集大项目】-附代码和课件

最全最详细数据结构与算法视频-【附课件和源码】

在这里插入图片描述

参考:

多进程https://www.cnblogs.com/kaituorensheng/p/4445418.html

发表评论

表情:
评论列表 (有 0 条评论,915人围观)

还没有评论,来说两句吧...

相关阅读

    相关 PyQt5篇】线

    这是因为QThread类提供了一个事件循环,可以在后台处理线程的任务,而不会影响到线程的响应性。,当在主线程中执行耗时操作时(例如click_1方法中的for循环),它。...

    相关 python进程线

    有关进程、线程、多进程、多线程 线程与进程 概念 线程:是程序执行流的最小单元,是系统独立调度和分配CPU(独立运行)的基本单位。 进程:是资源分配的基本

    相关 Python 线进程

    什么是线程? py文件在执行程序中,他会根据程序的编写来区分,假如没有创建子进程,整个程序就是主进程。 那程序中,有主线程而且还有子线程,那他就是一个多线程。 使用多