一、线程概念

在程序运行时,操作系统会创建一个进程,并且会创建一个线程,这个线程就是主线程,主线程可以创建子线程。线程看上去同时运行,其实是按照并发执行的,走走停停,一直到所有形线程完成为止。线程像进程一样会有生命周期,如下所示:

将程序进行多线程编程,其性能会得到很大提升。python线程对CPU密集型性能提高不大,对I/O密集型性能提高很大。

二、多线程示例

import threading

import time

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out() #加入执行的程序代码

def out():

print_time1()

print_time2()

def print_time1():

print("Locka is acquired")

print("Lockb is acwuired")

def print_time2():

print("Lockb is acquired")

time.sleep(2)

print("Locka is acwuired")

def main():

for i in range(50):

t = myThread()

t.start() #执行线程

main()

以上就是线程的简单程序,我们创建了50个线程,将他们同时运行。他们完成的时间不一样,其先后顺序也不能确定。使用方法就是自己写一个类,继承threading.Thread类,并重写方法run(),将自己要运行的程序放入run()函数之中就行。

但是,上述程序有一个问题,就是在调用函数out()时,可能在一个线程还没有执行完时,就暂停,CPU转而去执行另一个线程,导致另一个线程修改了这个线程的数据,导致输出错误的结果。解决办法就是在同一时刻就只能有一个线程访问临界资源,其他线程只能等待。

三、线程同步

在python中实现线程同步有多种方法

1. 线程锁(Lock)

GIL(全局解释器锁)

GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念,是为了实现不同线程对共享资源访问的互斥,才引入了GIL。以下是原理图:

我们对临界资源加上锁,这样其他线程就无法访问,直到这个线程完成操作,释放线程锁之后为止。如下代码:

import threading

import time

#创建锁

locka = threading.Lock()

lockb = threading.Lock()

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

locka.acquire() #获取锁

print("Locka is acquired")

lockb.acquire() #获取锁

print("Lockb is acwuired")

lockb.release() #释放锁

locka.release() #释放锁

def print_time2():

lockb.acquire()

print("Lockb is acquired")

time.sleep(2)

locka.acquire()

print("Locka is acwuired")

locka.release()

lockb.release()

def main():

for i in range(50):

t = myThread()

t.start()

main()

在上面程序中,我们创建了两个锁locka和lockb,分别对临界资源加锁,这样就可以让同一时刻就只有一个线程执行,避免输出错误结果。但是上述代码还有一个错误,当第一个线程执行到函数print_time2()的time_sleep(2)时,需要获取锁locka,但是locka已经被第二个线程获取,还没有释放,而且第二个线程也需要获取lockb才能继续运行,但是lockb已被第一个线程获取,还没有释放,就这样,两个线程会一直等待,陷入死锁。解决办法是引入可重入锁。

2.递归锁(RLock)

递归锁就是在同一个线程中可以获取锁所多次,不会陷入死锁。但是在acquire()n次之后,需要release()n次。

import threading

import time

rlock = threading.RLock() #RLock本身有一个计数器,如果碰到acquire,那么计数器+1

#如果计数器大于0,那么其他线程无法查收,如果碰到release,计数器-1

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

rlock.acquire() #获取锁

print("Locka is acquired")

rlock.acquire() #获取锁

print("Lockb is acwuired")

rlock.release() #释放锁

rlock.release() #释放锁

def print_time2():

rlock.acquire()

print("Lockb is acquired")

time.sleep(2)

rlock.acquire()

print("Locka is acwuired")

rlock.release()

rlock.release()

def main():

for i in range(50):

t = myThread()

t.start()

main()

三、Semaphore(信号量)

threading模块里的Semaphore类实现了信号量对象,可用于控制获取资源的线程数量。所具有的acquire()和release()方法,可以用with语句的上下文管理器。当进入时,将调用acquire()方法,当退出时,将调用release()。

import threading

import time

sem = threading.Semaphore(3) #设置线程并发数

class myThread(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

out()

def out():

print_time1()

print_time2()

def print_time1():

sem.acquire() #线程数减一

print("Locka is acquired")

print("Lockb is acwuired")

sem.release() #线程数加一

def print_time2():

sem.acquire() #线程数减一

print("Lockb is acquired")

print("Locka is acwuired")

sem.release() #线程数加一

def main():

for i in range(10):

t = myThread()

t.start()

main()

四、Condition(条件变量)

Condition(条件变量)通常与一个锁关联。需要在多个Contidion中共享一个锁时,可以传递一个Lock/RLock实例给构造方法,否则它将默认生成一个RLock实例。

可以认为,除了Lock带有的锁定池外,Condition还包含一个等待池,池中的线程处于状态图中的等待阻塞状态,直到另一个线程调用notify()/notifyAll()通知;得到通知后线程进入锁定池等待锁定。

Condition():

acquire(): 线程锁

release(): 释放锁

wait(timeout): 线程挂起,并释放锁,直到收到一个notify通知或者超时(可选的,浮点数,单位是秒s)才会被唤醒继续运行。wait()必须在已获得Lock前提下才能调用,否则会触发RuntimeError。

notify(n=1): 调用这个方法将从等待池挑选一个线程并通知,收到通知的线程将自动调用acquire()尝试获得锁定(进入锁定池);其他线程仍然在等待池中。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。 最多唤醒n个等待的线程。

notifyAll(): 调用这个方法将通知等待池中所有的线程,这些线程都将进入锁定池尝试获得锁定。调用这个方法不会释放锁定。使用前线程必须已获得锁定,否则将抛出异常。

以下就以生产者消费者为例:

import threading

import time

import random

con = threading.Condition()

class Goods():

def __init__(self):

self.__goods = 0

def getgoods(self):

return self.__goods

def add(self):

self.__goods += 1

def sub(self):

self.__goods -= 1

def isEmpty(self):

if self.__goods <= 0:

return True

else:

return False

def isFull(self):

if self.__goods >= 10:

return True

else:

return False

class Producer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

con.acquire()#获取锁

while goods.isFull(): #货物满了,需要消费才能生产,进入阻塞

con.wait()

goods.add()#生产一件货物

print("生产一件货物,总货物数量为:", goods.getgoods())

con.notifyAll()#生产一件货物后便唤醒所有正在等待的消费者

con.release()#释放锁

time.sleep(random.random())

class Consumer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

con.acquire()#获取锁

while goods.isEmpty():#货物消费完了,需要生产货物,进入阻塞

con.wait()

goods.sub()#消费一件货物

print("消费一件货物,总货物数量为:", goods.getgoods())

con.notifyAll()#消费一件货物后便唤醒所有正在等待的生产者

con.release()#释放锁

time.sleep(random.random())

goods = Goods()

def main():

threads = []

#threads.append(Producer())

#threads.append(Comsumer())

for i in range(5):

threads.append(Producer())

for i in range(5):

threads.append(Consumer())

for th in threads:

th.start()

main()

五、同步队列

让我们考虑更复杂的一种场景:产品是各不相同的。这时只记录一个数量就不够了,还需要记录每个产品的细节。很容易想到需要用一个容器将这些产品记录下来。

Python的Queue模块中提供了同步的、线程安全的队列类,包括FIFO(先入先出)队列Queue,LIFO(后入先出)队列LifoQueue,和优先级队列PriorityQueue。这些队列都实现了锁原语,能够在多线程中直接使用。可以使用队列来实现线程间的同步。

用FIFO队列实现上述生产者与消费者问题的代码如下:

import threading

import time

import random

import queue

q = queue.Queue() #创建一个线程同步队列

class Producer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

item = random.randint(0, 16)

while q.qsize() >= 10:

pass

q.put(item)    #添加货物

print("生产货物%02d, 队列大小:%02d" % (item, q.qsize()))

time.sleep(random.randint(0, 3))

class Consumer(threading.Thread):

def __init__(self):

threading.Thread.__init__(self)

def run(self):

while True:

item = q.get()   #消费货物,若为空,会阻塞

print("消费货物%02d, 队列大小:%02d" % (item, q.qsize()))

time.sleep(random.randint(0, 3))

def main():

threads = []

for i in range(5):

threads.append(Producer())

for i in range(5):

threads.append(Consumer())

for th in threads:

th.start()

main()

六、Event(事件)

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法wait、clear、set。

事件处理的机制:全局定义了一个“Flag”,如果“Flag”值为 False,那么当程序执行 event.wait 方法时就会阻塞,如果“Flag”值为True,那么event.wait 方法时便不再阻塞。

event.set() 设置标志位为True

event.clear() 清空标志位,标志位为False

event.wait() 等待设置标志位,阻塞

event.isSet() 判断标志位是True还是False

下面就采用红绿灯车通行的例子来示例:

import threading

import time

event = threading.Event()

def Lighter():

event.set()

count = 0

while True:

if count > 5 and count <= 10: #红灯

event.clear() #清除标志位

elif count > 10: #变为绿灯

event.set() #重新设置标志位

count = 0

time.sleep(1)

count += 1

def Car(name):

while True:

if event.isSet(): #判断标志位为True

print("light is green, %d is running" % name)

time.sleep(2)

else:

print("light is red, %d is waiting" % name)

event.wait() #阻塞,停车

def main():

light = threading.Thread(target=Lighter)

light.start()

threads = []

for i in range(5): #开五部车

threads.append(threading.Thread(target=Car, args=(i,)))

for car in threads:

car.start()

main()

这个程序将红绿灯的情况来控制车的通行,即用红绿灯这线程来控制车线程,达到一个线程控制多个线程的目的。

python多线程 不在main_Python多线程相关推荐

  1. python廖雪峰_【Python】python中实现多进程与多线程

    进程与线程 进程(process)就是任务,是计算机系统进行资源分配和调度的基本单位[1].比如,打开一个word文件就是启动了一个word进程. 线程(thread)是进程内的子任务.比如word中 ...

  2. python实用程序育儿法_Python多线程 简明例子

    Python多线程 简明例子 (2010-03-11 15:15:09) Python多线程 简明例子 综述 多线程是程序设计中的一个重要方面,尤其是在服务器Deamon程序方面.无论何种系统,线程调 ...

  3. python真正实现多线程的方法_python多线程几种方法实现

    匿名用户 1级 2018-05-27 回答 Python进阶(二十六)-多线程实现同步的四种方式 临界资源即那些一次只能被一个线程访问的资源,典型例子就是打印机,它一次只能被一个程序用来执行打印功能, ...

  4. python多线程没用_python的多线程到底有没有用?

    在群里经常听到这样的争执,有人是虚心请教问题,有人就大放厥词因为这个说python辣鸡.而争论的核心无非就是,python的多线程在同一时刻只会有一条线程跑在CPU里面,其他线程都在睡觉.这是真的吗? ...

  5. python程序默认执行与多线程

    一.程序执行流程和进程线程简述 1程序执行流程 有类似脚本程序或编程经验的同学都知道,程序默认是自上而下,从左到右的按顺序执行,也叫串行执行;而多线程类似于并行执行,即A模块(函数)执行时B也执行不需 ...

  6. python多线程爬虫实例-Python3多线程爬虫实例讲解代码

    多线程概述 多线程使得程序内部可以分出多个线程来做多件事情,充分利用CPU空闲时间,提升处理效率.python提供了两个模块来实现多线程thread 和threading ,thread 有一些缺点, ...

  7. Python 并发编程之使用多线程和多处理器

    在Python编码中我们经常讨论的一个方面就是如何优化模拟执行的性能.尽管在考虑量化代码时NumPy.SciPy和pandas在这方面已然非常有用,但在构建事件驱动系统时我们无法有效地使用这些工具.有 ...

  8. async python两个_【Python】python中实现多进程与多线程

    进程与线程 进程(process)就是任务,是计算机系统进行资源分配和调度的基本单位[1].比如,打开一个word文件就是启动了一个word进程. 线程(thread)是进程内的子任务.比如word中 ...

  9. Python爬虫进阶五之多线程的用法

    前言 我们之前写的爬虫都是单个线程的?这怎么够?一旦一个地方卡到不动了,那不就永远等待下去了?为此我们可以使用多线程或者多进程来处理. 首先声明一点! 多线程和多进程是不一样的!一个是 thread ...

最新文章

  1. 当你舌吻十秒后,下面就……
  2. 1.2.4 ORACLE_SID的含义
  3. [IE技巧] 如何让IE 启动的时候不加载任何插件
  4. android震动提示音,android的消息提示(震动与提示音)
  5. 帆软报表(finereport)图表钻取详细类别 当前页对话框展示
  6. MySQL----示例知识点整理
  7. linux 新建用户、用户组 以及为新用户分配权限
  8. MySQL安装错误——Access denied for user 'root'@'localhost' (using password: YES)
  9. 手机如何访问电脑局域网文件共享服务器,数据共享 手机怎么访问电脑文件?多个设备之间数据共享...
  10. 疫情病毒全部“抹杀”?用数据模型来解读传播抑制的效果差异!
  11. linux HZ 值_Linux操作系统中进程的操作命令(ps,kill,keep)
  12. 线切割常用专用编程软件下载
  13. 增长智能引领营销数字化,数字中台掌控消费者旅程
  14. 日本转运海淘包裹被税、退运处理流程详解—北京篇
  15. 轩小陌的Python笔记-day14 自定义模块、第三方模块、内置模块(部分)
  16. Pytorch之nn.Conv1d学习个人见解
  17. 在 Java 中如何加快大型集合的处理速度
  18. IOT开发的学习-linux#5 gcc编译生成一个c语言实行文件,用sh调用实行
  19. 华硕飞行堡垒6打开tpm
  20. 网络工程师月入五万难不难?

热门文章

  1. 普211标准三维EE零基础转CS申
  2. 数据的设计命名的十个要点
  3. PowerDesigner显示注释字段问题
  4. Delphi中DLL初始化和退出处理
  5. (2)ARM Cortex-M3指令集
  6. Spring AOP进行日志记录,管理
  7. 【C/C++多线程编程之三】创建pthread线程
  8. 日常生活 -- 嵌入式面试
  9. LIVE555再学习 -- 初识
  10. DM368开发 -- 制作ubifs文件系统