2018年8月25日多线程编程总结

今天遇到的新单词: grid   n格子,方格,坐标 stick  n插入

PYTHON 本身也支持多任务处理,并且提供了如下的操作方式 多线程多任务处理机制   (比较常用) 多进程多任务处理机制   (不常用,大型项目开发或者系统开发会用) 协程多任务处理机制       (不常用)

线程等于微进程,协程等于微线程

多线程总结: python中提供了两个模块支持多线程,分别是thread和threading,但是thread模块过于底层,对于新手 来说并不是特别的友好,要求多线程的程序开发逻辑思维清晰同时又具备大量开发经验的 情况下,可以控制的非常精细,PYTHON3 中将 thread 模块进行了规范内置,更名为_thread,友好的提醒如果你不是并发编 程的骨灰级爱好者,请不要轻易尝试使用_thread 进行操作,而是推荐使用操作更加灵活使 用更加简洁的 threading 模块进行并发编程的处理,下面详细讲解threading模块:

多线程编程需要引入threading模块: import threading

threading 模块的属性和方法 名称             描述 Thread            线程类,用于创建和管理线程 Event              事件类,用于线程同步 Condition        条件类,用于线程同步 Lock/RLock     锁类,用于线程同步 Timer              延时线程,用于在一定事件后执行一个函数 Semaphore/BoundedSemaphore  信号量类,用于线程同步 active_count()/activeCount()  获取当前 alive 状态的所有线程数量 current_thread()/currentThread()  获取当期正在执行的线程对象 get_ident()         获取运行中程序当前线程的唯一编号 enumerate()      获取所有 alive 状态线程列表 local                  线程局部数据类 stack_size([size])  获取线程占用内存栈的大小 main_thread()   获取主线程

用法展示: #获取当前存活的线程的总数,该数量包括并发的线程和主线程的总数 t = threading.activeCount()    print(t)

# 获取当前线程对象【线程名称】 print(threading.current_thread()) print(threading.current_thread().getName()) print(threading.get_ident())

# 获取主线程对象 print(threading.main_thread()) print(threading.main_thread().getName())

Thread 类型的属性和方法 名称             描述 __init__(name,target,args,kwargs)  构造方法,创建线程类型 is_alive()/isAlive()   判断当前线程是否 alive 状态 run()                  线程执行方法,面向对象自定义线程必须重写该函数 start()                线程启动方法 join([timeout=None])   线程独占,等待当前线程运行结束或者超时才能执行其他线程 ident                  标识当前线程的唯一编号 name                 当前线程名称 daemon             布尔值,判断当前线程是否守护线程 (_thread模块默认是守护的   threading模块默认是不守护的   multiprocessing默认是不守护的)

#创建一个线程: t1 = threading.Thread(name="线程1", target=sing) 创建线程的时候一定要事先创建一个函数,用于线程的target.

#判断指定的线程是否存活,返回True是存活,返回False是死亡 print(t1.is_alive())

#独占属性:让指定的线程独占CPU时间片,知道当前线程运行结束/超时 t1.join()

#获取指定线程的编号 t1.ident

#启动线程 t1.start()

#守护属性,thrading模块中默认是不守护的,不过可以修改守护属性的值。 t1.daemon = True 这时就将线程1的守护属性设为了守护,当主线程运行完之后,无论t1线程时是否 运行结束t1都会跟着运行结束

#获取指定线程的名字 t1.name

#创建多个线程: for i in range(5):     t = threading.Thread(name="线程"+str(i), target=sing)     t.start() #获取当前线程的名字 print(threading.current_thread().getName())

面向过程编程:

加锁解锁:案例火车票售票问题: 锁分为互斥锁(Lock())和可重用锁(RLock()) lock1 = threading.Lock() lock2 = threading.Rlock() 面向过程的多线程编程需要加锁来解决多线程数据的共享问题,但是需要注意死锁的出现 lock = threading.Lock()先创建一个锁对象 lock.acquire()加锁 lock.release()解锁 死锁问题的案例是哲学家吃饭问题: 因为哲学家A和哲学家B是两个线程,对各自的数据重复上锁,可能会导致死锁的问题存在,让程序无法 继续向下运行,处于一种永久等待的状态。

为了解决线程之间的数据访问和线程之间的通信问题,python提供了多线程同步事件对象和多线程同步条件对象, 常用的是条件对象,不过python也提供队列的数据类型,安全访问数据不会造成线程的冲突。所以队列更常用。 1.事件对象,案例卖油条买油条: 事件对象不需要加锁来解决数据的共享问题,但是需要添加标记,清除标记和等待事件 event = threading.Event()   #创建一个事件对象 在编程过程中需要用到让对方线程等待或者唤醒的事件 等待是:event.wait() 打标记就相当于唤醒对方的wait,打标记的方式是: event.set() event.clear() 打完标记之后需要立即清除,如果不清除的话该线程下面的等待语句不会执行,整个的流程语句 会一下子执行完,set打完标记之后本线程的语句会执行到wait语句,对方线程的语句可以执行wait 语句之后的语句

2.条件对象,案例生产者和消费者问题: 多线程同步条件对象需要加锁和等待唤醒来解决数据的共享问题,加锁的方式和普通的多线程编程方式不同: con = threading.Condition()   #创建一个条件对象 con.acquire()加锁 con.release()解锁 同时线程有等待和唤醒两种操作: 线程的等待:con.wait()   /  con.wait_for() 线程的唤醒:con.notify() /  con.notify_all()

多线程之间的数据共享: 多线程并发编程的重点是解决线程之间访问共享数据和线程之间通信的问题 为了解决线程之间数据共享问题,PYTHON 提供了一个数据类型【队列】可以用于在多线程 并发模式下,安全的访问数据而不会造成数据共享冲突,队列是由queue模块提供的Queue类型创建: 它的特性是当一个线程正在访问队列时,队列会自动拒绝其他线程的访问 队列主要有两个方法: put(data, [timeout=None])  向队列中添加数据,队列如果满了,一直阻塞直到超时或者队     列中有数据被删除之后添加成功 get([timeout=None])  从队列中获取数据,如果队列为空,一直阻塞直到超时或者队 列中添加数据之后获取成功

basket = queue.Queue(10)  #生成一个队列

向队列中添加数据: no = random.randint(0, 10) basket.put(no, timeout=1) 从队列中取数据: no2 = basket.get(timeout=1)

当遇到比较大项目的多线程并发编程时,可以使用面向对象的多线程编程 面向对象多线程编程的基本语法:                                          面向对象创建多线程时,不需要用t1=threading.Thread(name,target,args),而是自定义一个类,继承threading.Thread类型, 先初始化一下函数,继承自父类,然后重写Thread类型的run方法,在run方法中填写想要执行的程序,写完之后 实例化自定义类的对象就直接可以产生一个线程,然后对象名.start()可以直接启动线程,start方法会自动启动run方法, 不需要专门去调用run方法。 面向对象多线程编程中需要定义锁对象,然后对数据进行加锁和解锁操作 lock = threading.Lock() con.acquire()加锁 con.release()解锁

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏北京马哥教育

Linux 中命令链接操作符,让你的代码更简洁!

Linux命令中链接的意思是,通过操作符的行为将几个命令组合执行。Linux中的链接命令,有些像你在shell中写短小的shell脚本,并直接在终端中执行。链接...

802
来自专栏Python小屋

使用with关键字让你的Python代码更加Pythonic

首先解释一下上一篇文章Python科学计算扩展库numpy中的广播运算中最后的小题目,该题目答案是一个元组(True, 5),原因在于Python中的等号=虽然...

3618
来自专栏cloudskyme

gsoap开发webservice

gSOAP编译工具提供了一个SOAP/XML 关于C/C++ 语言的实现,从而让C/C++语言开发web服务或客户端程序的工作变得轻松了很多。绝大多数的C++w...

3376
来自专栏轻量级微服务

微服务下跨语言 RPC 实现

目前主流的 Java 开发框架 Spring Boot,为了更方便集成 gRPC,自己开发了 spring-boot-starter-grpc,仅需简单的几行配...

2423
来自专栏bboysoul

linux下如何编译带有math.h头文件的程序

环境是centos7 大概意思是没有定义sqrt函数 百度要自己去指定头文件去编译命令如下: gcc [文件名] -lm 参数解释 -l 指定程序链接...

923
来自专栏C/C++基础

Linux命令(31)——find命令

find命令用于在指定目录查找文件,可以指定一些匹配条件,如按文件名、文件类型、用户甚至是时间戳来查找文件。

1324
来自专栏C/C++基础

C++覆盖或删除指定位置的文件内容

我们经常使用ofstream或者fstream可写文件,使用ifstream可以写文件,但需要设置文件的打开状态为ios::out。C++中IO流打开模式使用位...

1303
来自专栏Python绿色通道

Python的进程

Python实现多进程的方式主要有两种:一种方法是使用os模块中的fork方法; 另一种是使用multiprocessing模块。这两种方法的区别在于前者仅适用...

972
来自专栏程序员同行者

django rest framework mixins小结

由上图可以看出这个类的一个逻辑,其中,perform_create( )对serializer直接进行save保存,当在一些情境下,我们需要对perform...

1583
来自专栏小筱月

shell 文本操作命令

:s/old/new/g 将当前行中查找到的所有字符串“old” 替换为“new”

1282

扫码关注云+社区

领取腾讯云代金券