Python多线程实现同步的四种方式


Posted in Python onMay 02, 2017

临界资源即那些一次只能被一个线程访问的资源,典型例子就是打印机,它一次只能被一个程序用来执行打印功能,因为不能多个线程同时操作,而访问这部分资源的代码通常称之为临界区。

锁机制

threading的Lock类,用该类的acquire函数进行加锁,用realease函数进行解锁

import threading
import time

class Num:
  def __init__(self):
    self.num = 0
    self.lock = threading.Lock()
  def add(self):
    self.lock.acquire()#加锁,锁住相应的资源
    self.num += 1
    num = self.num
    self.lock.release()#解锁,离开该资源
    return num

n = Num()
class jdThread(threading.Thread):
  def __init__(self,item):
    threading.Thread.__init__(self)
    self.item = item
  def run(self):
    time.sleep(2)
    value = n.add()#将num加1,并输出原来的数据和+1之后的数据
    print(self.item,value)

for item in range(5):
  t = jdThread(item)
  t.start()
  t.join()#使线程一个一个执行

当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“同步阻塞”(参见多线程的基本概念)。

直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。

信号量

信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,如果内部计数器等于0,则会阻塞该线程,知道有线程调用了release方法将内部计数器更新到大于1位置。

import threading
import time
class Num:
  def __init__(self):
    self.num = 0
    self.sem = threading.Semaphore(value = 3)
    #允许最多三个线程同时访问资源

  def add(self):
    self.sem.acquire()#内部计数器减1
    self.num += 1
    num = self.num
    self.sem.release()#内部计数器加1
    return num

n = Num()
class jdThread(threading.Thread):
  def __init__(self,item):
    threading.Thread.__init__(self)
    self.item = item
  def run(self):
    time.sleep(2)
    value = n.add()
    print(self.item,value)

for item in range(100):
  t = jdThread(item)
  t.start()
  t.join()

条件判断

所谓条件变量,即这种机制是在满足了特定的条件后,线程才可以访问相关的数据。

它使用Condition类来完成,由于它也可以像锁机制那样用,所以它也有acquire方法和release方法,而且它还有wait,notify,notifyAll方法。

"""
一个简单的生产消费者模型,通过条件变量的控制产品数量的增减,调用一次生产者产品就是+1,调用一次消费者产品就会-1.
"""

"""
使用 Condition 类来完成,由于它也可以像锁机制那样用,所以它也有 acquire 方法和 release 方法,而且它还有
wait, notify, notifyAll 方法。
"""

import threading
import queue,time,random

class Goods:#产品类
  def __init__(self):
    self.count = 0
  def add(self,num = 1):
    self.count += num
  def sub(self):
    if self.count>=0:
      self.count -= 1
  def empty(self):
    return self.count <= 0

class Producer(threading.Thread):#生产者类
  def __init__(self,condition,goods,sleeptime = 1):#sleeptime=1
    threading.Thread.__init__(self)
    self.cond = condition
    self.goods = goods
    self.sleeptime = sleeptime
  def run(self):
    cond = self.cond
    goods = self.goods
    while True:
      cond.acquire()#锁住资源
      goods.add()
      print("产品数量:",goods.count,"生产者线程")
      cond.notifyAll()#唤醒所有等待的线程--》其实就是唤醒消费者进程
      cond.release()#解锁资源
      time.sleep(self.sleeptime)

class Consumer(threading.Thread):#消费者类
  def __init__(self,condition,goods,sleeptime = 2):#sleeptime=2
    threading.Thread.__init__(self)
    self.cond = condition
    self.goods = goods
    self.sleeptime = sleeptime
  def run(self):
    cond = self.cond
    goods = self.goods
    while True:
      time.sleep(self.sleeptime)
      cond.acquire()#锁住资源
      while goods.empty():#如无产品则让线程等待
        cond.wait()
      goods.sub()
      print("产品数量:",goods.count,"消费者线程")
      cond.release()#解锁资源

g = Goods()
c = threading.Condition()

pro = Producer(c,g)
pro.start()

con = Consumer(c,g)
con.start()

同步队列

put方法和task_done方法,queue有一个未完成任务数量num,put依次num+1,task依次num-1.任务都完成时任务结束。

import threading
import queue
import time
import random

'''
1.创建一个 Queue.Queue() 的实例,然后使用数据对它进行填充。
2.将经过填充数据的实例传递给线程类,后者是通过继承 threading.Thread 的方式创建的。
3.每次从队列中取出一个项目,并使用该线程中的数据和 run 方法以执行相应的工作。
4.在完成这项工作之后,使用 queue.task_done() 函数向任务已经完成的队列发送一个信号。
5.对队列执行 join 操作,实际上意味着等到队列为空,再退出主程序。
'''

class jdThread(threading.Thread):
  def __init__(self,index,queue):
    threading.Thread.__init__(self)
    self.index = index
    self.queue = queue

  def run(self):
    while True:
      time.sleep(1)
      item = self.queue.get()
      if item is None:
        break
      print("序号:",self.index,"任务",item,"完成")
      self.queue.task_done()#task_done方法使得未完成的任务数量-1

q = queue.Queue(0)
'''
初始化函数接受一个数字来作为该队列的容量,如果传递的是
一个小于等于0的数,那么默认会认为该队列的容量是无限的.
'''
for i in range(2):
  jdThread(i,q).start()#两个线程同时完成任务

for i in range(10):
  q.put(i)#put方法使得未完成的任务数量+1

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python下载指定页面上图片的方法
May 12 Python
Python实现对象转换为xml的方法示例
Jun 08 Python
python通过socket实现多个连接并实现ssh功能详解
Nov 08 Python
简单实现python聊天程序
Apr 01 Python
详解Python3网络爬虫(二):利用urllib.urlopen向有道翻译发送数据获得翻译结果
May 07 Python
python实现本地批量ping多个IP的方法示例
Aug 07 Python
10行Python代码计算汽车数量的实现方法
Oct 23 Python
python3 requests库实现多图片爬取教程
Dec 18 Python
如何在python开发工具PyCharm中搭建QtPy环境(教程详解)
Feb 04 Python
python调用HEG工具批量处理MODIS数据的方法及注意事项
Feb 18 Python
Python使用Pygame绘制时钟
Nov 29 Python
Python matplotlib可视化之绘制韦恩图
Feb 24 Python
Python之Web框架Django项目搭建全过程
May 02 #Python
python3实现抓取网页资源的 N 种方法
May 02 #Python
Pycharm学习教程(2) 代码风格
May 02 #Python
Pycharm学习教程(1) 定制外观
May 02 #Python
pycharm安装图文教程
May 02 #Python
python安装教程 Pycharm安装详细教程
May 02 #Python
python处理xml文件的方法小结
May 02 #Python
You might like
Zend公司全球首推PHP认证
2006/10/09 PHP
剖析 PHP 中的输出缓冲
2006/12/21 PHP
php正则表达式(regar expression)
2011/09/10 PHP
解决phpmyadmin中缺少mysqli扩展问题的方法
2013/05/06 PHP
PHP防止跨域提交表单
2013/11/01 PHP
PHP实用函数分享之去除多余的0
2015/02/06 PHP
浅析Yii2 gridview实现批量删除教程
2016/04/22 PHP
深入理解PHP之源码目录结构与功能说明
2016/06/01 PHP
Javascript表达式中连续的 &amp;&amp; 和 || 之赋值区别
2010/10/17 Javascript
让新消息在网页标题闪烁提示的jQuery代码
2013/11/04 Javascript
js身份证判断方法支持15位和18位
2014/03/18 Javascript
防止登录页面出现在frame中js代码
2014/07/22 Javascript
javascript根据时间生成m位随机数最大13位
2014/10/30 Javascript
javascript获取文档坐标和视口坐标
2015/05/26 Javascript
浅谈setTimeout 与 setInterval
2015/06/23 Javascript
jQuery手动点击实现图片轮播特效
2020/04/20 Javascript
angularjs的select使用及默认选中设置
2017/04/08 Javascript
ligerUI---ListBox(列表框可移动的实例)
2017/11/28 Javascript
浅析js实现网页截图的两种方式
2019/11/01 Javascript
Vue基础配置讲解
2019/11/29 Javascript
vue路由传参的基本实现方式小结【三种方式】
2020/02/05 Javascript
基于 Vue 的 Electron 项目搭建过程图文详解
2020/07/22 Javascript
Python设计模式编程中Adapter适配器模式的使用实例
2016/03/02 Python
python实点云分割k-means(sklearn)详解
2020/05/28 Python
Python环境管理virtualenv&amp;virtualenvwrapper的配置详解
2020/07/01 Python
Django Form常用功能及代码示例
2020/10/13 Python
乐高积木玩具美国官网:LEGO Shop US
2016/09/16 全球购物
J.Crew官网:美国知名休闲服装品牌
2017/05/19 全球购物
自荐信格式技巧有哪些呢
2013/11/19 职场文书
卫校中专生的自我评价
2014/01/15 职场文书
销售顾问岗位职责
2014/02/25 职场文书
2014基层党员干部学习全国两会心得体会
2014/03/17 职场文书
爱国主义教育活动总结
2014/05/07 职场文书
八荣八耻的活动方案
2014/08/16 职场文书
2014年加油站站长工作总结
2014/12/23 职场文书
2015年感恩节活动总结
2015/03/24 职场文书