Python多线程编程之threading模块详解
作者:汪酱努力提升打工ing 发布时间:2023-12-28 07:52:59
标签:python,threading,模块,多线程
一、介绍
线程是什么?线程有啥用?线程和进程的区别是什么?
线程是操作系统能够进行运算调度的最小单位。被包含在进程中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
二、Python如何创建线程
2.1 方法一:
创建Thread对象
步骤:
1.目标函数
2.实例化Thread对象
3.调用start()方法
import threading
# 目标函数1
def fun1(num):
for i in range(num):
print('线程1: 第%d次循环:' % i)
# 目标函数2
def fun2(lst):
for ele in lst:
print('线程2: lst列表中元素 %d' % ele)
def main():
num = 10
# 实例化Thread对象
# target参数一定为一个函数,且不带括号
# args参数为元组类型,参数为一个时一定要加逗号
t1 = threading.Thread(target=fun1, args=(num,))
t2 = threading.Thread(target=fun2, args=([1, 2, 3, 4, 5],))
# 调用start方法
t1.start()
t2.start()
if __name__ == '__main__':
main()
2.2 方法二:
创建子类继承threading.Thread类
import threading
import os
class Person(threading.Thread):
def run(self):
self.sing(5)
self.cook()
@staticmethod
def sing(num):
for i in range(num):
print('线程[%d]: The person sing %d song.' % (os.getpid(), i))
@staticmethod
def cook():
print('线程[%d]:The person has cooked breakfast.' % os.getpid())
def main():
p1 = Person()
p1.start()
p2 = Person()
p2.start()
if __name__ == '__main__':
main()
三、线程的用法
3.1 确定当前的线程
import threading
import time
import logging
def fun1():
print(threading.current_thread().getName(), 'starting')
time.sleep(0.2)
print(threading.current_thread().getName(), 'exiting')
def fun2():
# print(threading.current_thread().getName(), 'starting')
# time.sleep(0.3)
# print(threading.current_thread().getName(), 'exiting')
logging.debug('starting')
time.sleep(0.3)
logging.debug('exiting')
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] (%(threadName)-10s) %(message)s'
)
def main():
t1 = threading.Thread(name='线程1', target=fun1)
t2 = threading.Thread(name='线程2', target=fun2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
3.2 守护线程
区别
普通线程:主线程等待子线程关闭后关闭
守护线程:管你子线程关没关,主线程到时间就关闭
守护线程如何搞
方法1:构造线程时传入dameon=True
方法2:调用setDaemon()方法并提供参数True
import threading
import time
import logging
def daemon():
logging.debug('starting')
# 添加延时,此时主线程已经退出,exiting不会打印
time.sleep(0.2)
logging.debug('exiting')
def non_daemon():
logging.debug('starting')
logging.debug('exiting')
logging.basicConfig(
level=logging.DEBUG,
format='[%(levelname)s] (%(threadName)-10s) %(message)s'
)
def main():
# t1 = threading.Thread(name='线程1', target=daemon)
# t1.setDaemon(True)
t1 = threading.Thread(name='线程1', target=daemon, daemon=True)
t2 = threading.Thread(name='线程2', target=non_daemon)
t1.start()
t2.start()
# 等待守护线程完成工作需要调用join()方法,默认情况join会无限阻塞,可以传入浮点值,表示超时时间
t1.join(0.2)
t2.join(0.1)
if __name__ == '__main__':
main()
3.3控制资源访问
目的:
Python线程中资源共享,如果不对资源加上互斥锁,有可能导致数据不准确。
import threading
import time
g_num = 0
def fun1(num):
global g_num
for i in range(num):
g_num += 1
print('线程1 g_num = %d' % g_num)
def fun2(num):
global g_num
for i in range(num):
g_num += 1
print('线程2 g_num = %d' % g_num)
def main():
t1 = threading.Thread(target=fun1, args=(1000000,))
t2 = threading.Thread(target=fun1, args=(1000000,))
t1.start()
t2.start()
if __name__ == '__main__':
main()
time.sleep(1)
print('主线程 g_num = %d' % g_num)
互斥锁
import threading
import time
g_num = 0
L = threading.Lock()
def fun1(num):
global g_num
L.acquire()
for i in range(num):
g_num += 1
L.release()
print('线程1 g_num = %d' % g_num)
def fun2(num):
global g_num
L.acquire()
for i in range(num):
g_num += 1
L.release()
print('线程2 g_num = %d' % g_num)
def main():
t1 = threading.Thread(target=fun1, args=(1000000,))
t2 = threading.Thread(target=fun1, args=(1000000,))
t1.start()
t2.start()
if __name__ == '__main__':
main()
time.sleep(1)
print('主线程 g_num = %d' % g_num)
互斥锁引发的另一个问题:死锁
死锁产生的原理:
import threading
import time
g_num = 0
L1 = threading.Lock()
L2 = threading.Lock()
def fun1():
L1.acquire(timeout=5)
time.sleep(1)
L2.acquire()
print('产生死锁,并不会打印信息')
L2.release()
L1.release()
def fun2():
L2.acquire(timeout=5)
time.sleep(1)
L1.acquire()
print('产生死锁,并不会打印信息')
L1.release()
L2.release()
def main():
t1 = threading.Thread(target=fun1)
t2 = threading.Thread(target=fun2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
time.sleep(1)
print('主线程 g_num = %d' % g_num)
如何避免产生死锁:
锁超时操作
import threading
import time
g_num = 0
L1 = threading.Lock()
L2 = threading.Lock()
def fun1():
L1.acquire()
time.sleep(1)
L2.acquire(timeout=5)
print('超时异常打印信息1')
L2.release()
L1.release()
def fun2():
L2.acquire()
time.sleep(1)
L1.acquire(timeout=5)
print('超时异常打印信息2')
L1.release()
L2.release()
def main():
t1 = threading.Thread(target=fun1)
t2 = threading.Thread(target=fun2)
t1.start()
t2.start()
if __name__ == '__main__':
main()
time.sleep(1)
print('主线程 g_num = %d' % g_num)
来源:https://blog.csdn.net/qq_31385393/article/details/115873831


猜你喜欢
- 这篇文章主要介绍了Python globals()和locals()对比详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 教你如何清除SQL日志 1.打开查询分析器,输入命令DUMP TRANSACTION 数据库名 WITH NO_LOG2. 再打开企业管理器
- 1.模型类中设置:null=True,表示数据库创建时该字段可不填,用NULL填充.MySQL:Null这一列,如果值为YES表示:创建一条
- 重装电脑,在windows和虚拟机里面的Ubuntu里都安装了Pycharm专业版,安装的时候我都选择了vim插件,装好之后打开发现ctrl
- CSS+DIV是网站标准(或称“WEB标准”)中常用的术语之一,通常为了说明与HTML网页设计语言中的表格(table)定位方式的区别,因为
- urllib 是 python 的内置模块, 主要用于处理url相关的一些操作,例如访问url、解析url等操作。urllib 包下面的 r
- 简介Part1:写在最前 OneProxy平民软件完全自主开发的分布式数据访问层,帮助用户在MySQL/
- 本文实例讲述了Python实现压缩与解压gzip大文件的方法。分享给大家供大家参考,具体如下:#encoding=utf-8#author:
- 在实际生活中,经常会有文件重复的困扰,即同一个文件可能既在A目录中,又在B目录中,更可恶的是,即便是同一个文件,文件名可能还不一样。在文件较
- 写在前面最近在使用Mockjs作为项目里面mock数据的工具,发现mockjs做的拦截部分是自己实现摸拟了一个XMLHttpRequest的
- pycharm 2020.1.2激活工具下载以及破解方法 免费可用至2089年需要提前安装好IDEA,官网下载地址:https://www.
- 如果你想让你的IIS支持wml,做个wap网站,只需作小小的改变就行了.虽然目前支持wml的虚拟主机极少,但是自己在本机上玩玩也好的.首先在
- 本文实例讲述了flask框架视图函数用法。分享给大家供大家参考,具体如下:flask框架 视图函数当中 各种实用情况简单配置1 建立连接2
- 锁是指在某组资源中,两个或两个以上的线程在执行过程中,在争夺某一资源时而造成互相等待的现象,若无外力的作用下,它们都将无法推进下去,死时就可
- 具体用法:1、<%= Counters.Get(CounterName) %>显示计数器的值。2、<% counterva
- 本文实例讲述了Python实现字符串格式化输出的方法。分享给大家供大家参考,具体如下:python属于强类型的语言,如果像java一样操作字
- 看代码吧~# 加载库import numpy as npfrom fancyimpute import KNNfrom sklearn.pr
- 最近老婆大人的公司给老婆大人安排了一个根据关键词查询google网站排名的差事。老婆大人的公司是做seo的,查询的关键词及网站特别的多,看着
- 内置方法 说明 __init__(self,...) 初始化对象,在创建新对象时调用 __del__(self) 释放对
- 本文实例讲述了Python3将jpg转为pdf文件的方法。分享给大家供大家参考,具体如下:#coding=utf-8#!/usr/bin/e