`
OrangeHolic
  • 浏览: 260923 次
  • 来自: 北京
社区版块
存档分类
最新评论

Python多线程和Python的锁

阅读更多
Python多线程
Python中实现多线程有两种方式,一种基于_thread模块(在Python2.x版本中为thread模块,没有下划线)的start_new_thread()函数,另一种基于threading模块的Thread类。
其实Python的多线程编程不能真正利用多核的CPU,但是用开源模块使你的计算压力分布到多核CPU上.........

一.使用start_new_thread()实现线程,是比较底层的实现方式,所有线程共享他们global数据,为了达到同步,模块也提供了简单的锁机制
_thread.start_new_thread(function, args[, kwargs])
启动一个新的进程,并返回其标识符. 线程执行的函数需要的参数由args(必须为一个元组)提供,亦可通过可选参数kwargs提供关键字参数组  成的字典。当函数返回时,启动的线程也   停止退出。如果函数中存在未处理异常,会打印堆栈跟踪后线程停止退出(其他线程继续执行)。

其中线程标识符是一个非0整数,并没有直接意思,可以当作从一个线程组成的特殊字典中索引本线程的一个key,也可用_thread.get_ident()得到,在线程退出后,标识符会被系统回收。在线程执行过程中可以调用_thread.exit()终止本线程的执行。

import _thread
import time
def threadFunction(count):
    for i in range(count):
      print('进程id为%d的打印%d'%(_thread.get_ident(),i))
      i-=1
      time.sleep(0.1)

def begin():
  ident1=_thread.start_new_thread(threadFunction,(100,))
  print('启动标识符为%d的进程'%(ident1,))
  ident2=_thread.start_new_thread(threadFunction,(100,))
  print('启动标识符为%d的进程'%(ident2,))

 
if __name__ == '__main__':
  begin()



二.使用Thread类来实现多线程,这种方式是对_thread模块(如果没有_thread,则为dummy_threading)的高级封装,在这种方式下我们需创建新类继承threading.Thread,和java一样重写threading.Thread的run方法即可.启动线程用线程的start方法,它会调用我们重写的run方法.
class MyThread(threading.Thread):
    '''只能重写__init__ 和 run 两个方法'''
    def __init__(self,name):
        threading.Thread.__init__(self)
        self.name=name
        self.bool_stop=False
    def run(self):
        while not self.bool_stop:
            print('进程%s,于%s'%(self.name,time.asctime()))
            time.sleep(1)
    def stop(self):
        self.bool_stop = True


if __name__ == '__main__':
    th1=MyThread('one')
    th2=MyThread('two')
    th1.start()
    th2.start()



Thread类还定义了以下常用方法与属性:

Thread.getName() \Thread.setName()
老方式用于获取和设置线程的名称,官方建议用Thread.name替代
Thread.ident
获取线程的标识符。只有在调用start()方法执行后才有效,否则返回None。
Thread.is_alive()
判断线程是否是激活的。
Thread.join([timeout])
调用Thread.join将会使主调线程堵塞,直到被调用线程运行结束或超时。参数timeout是一个数值类型,表示超时时间,如果未提供该参数,那么主调线程将一直堵塞到被调线程结束。


Python中的锁

先用_thread模块的Lock锁来实现生产者消费者问题,Lock对象是Python提供的低级线程控制工具,使用起来非常简单,只需下面3条语句即可:
_thread.allocate_lock()返回一个新Lock对象,即为一个新锁
lock.acquire() 相当于P操作,得到一个锁,
lock.release()相当于V操作,释放一个锁

代码如下:
import _thread,time,random
dish=0
lock = _thread.allocate_lock()
def producerFunction():
   '''如果投的筛子比0.2大,则向盘子中增加一个苹果'''
   global lock,dish
   while True:
       if(random.random() > 0.1):
         lock.acquire()
         if dish < 100:
           dish+=1
           print('生产者增加了一个苹果,现在有%d个苹果'%(dish,))
         lock.release()
         time.sleep(random.random()*3)

def consumerFunction():
  '''如果投的筛子比0.5大,则从盘子中取一个苹果'''
  global lock,dish
  while True:
    if(random.random() > 0.9):
      lock.acquire()
      if dish > 0:
        dish-=1
        print('消费者拿走一个苹果现,在有%d个苹果'%(dish,))
      lock.release()
      time.sleep(random.random()*3)

def begin():
  ident1=_thread.start_new_thread(producerFunction,())
  ident2=_thread.start_new_thread(consumerFunction,()) 
if __name__ == '__main__':
  begin()

另一个较高级的锁为RLock锁,RLock对象内部维护着一个Lock对象,它是一种可重入的对象。对于Lock对象而言,如果一个线程连续两次进行acquire操作,那么由于第一次acquire之后没有release,第二次acquire将挂起线程。这会导致Lock对象永远不会release,使得线程死锁。RLock对象允许一个线程多次对其进行acquire操作,因为在其内部通过一个counter变量维护着线程acquire的次数。而且每一次的acquire操作必须有一个release操作与之对应,在所有的release操作完成之后,别的线程才能申请该RLock对象。


threading模块对Lock也提供和封装,提供了更高级的同步方式(可以理解为更高级的锁),包括threading.Event和threading.Condition,其中threading.Event为提供了简单的同步方式:一个进程标记event,其他进程等待,只需下面的几个方法即可:
Event.wait([timeout])
堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。
Event.set()
将标识号设为Ture
Event.clear()
设为标识符False


threading.Condition 可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题。threadiong.Condition在内部维护一个琐对象(默认是RLock),可以在创建Condigtion对象的时候把琐对象作为参数传入。Condition也提供了acquire, release方法,其含义与琐的acquire, release方法一致,其实它只是简单的调用内部琐对象的对应的方法而已。Condition还提供了如下方法(特别要注意:这些方法只有在占用琐(acquire)之后才能调用,否则将会报RuntimeError异常。):
Condition.wait([timeout]):    
wait方法释放内部所占用的琐,同时线程被挂起,直至接收到通知被唤醒或超时(如果提供了timeout参数的话)。当线程被唤醒并重新占有琐的时候,程序才会继续执行下去。
Condition.notify():  
唤醒一个挂起的线程(如果存在挂起的线程)。注意:notify()方法不会释放所占用的琐。
Condition.notify_all()
唤醒所有挂起的线程(如果存在挂起的线程)。注意:这些方法不会释放所占用的琐。






分享到:
评论

相关推荐

    python多线程同步之文件读写控制

    总结来说,Python中的多线程同步在文件读写控制中起到关键作用,防止数据不一致和错误。通过使用`threading.Lock`,我们可以确保在读写文件时只有一个线程在执行,从而保证了数据的正确性和文件操作的顺序。在多线程...

    基于Linux的python多线程爬虫程序设计.pdf

    此外,相比于依赖开放API的爬虫程序,基于Linux和Python多线程的爬虫程序在长期运行中显示出更好的性能。 在实现多线程爬虫时,需要考虑到多线程的同步和数据一致性问题。由于多线程程序在执行时会共享内存资源,...

    python多线程编程实现网络串口透传

    在Python多线程编程中,需要注意GIL(全局解释器锁)的存在,虽然Python的多线程在CPU密集型任务上可能表现不佳,但在I/O密集型任务(如网络和串口通信)中,由于线程间等待I/O的时间较长,多线程仍能有效提高程序...

    python 多线程实现多个网址的多次快速访问

    此外,Python的全局解释器锁(GIL)可能会限制多线程在CPU密集型任务上的性能提升。如果需要进一步提升性能,可以考虑使用多进程或异步IO(如`asyncio`库)。 总结,通过Python的多线程,我们可以有效地实现对多个...

    Python 多线程编程实例

    Python 多线程编程实例,一个综合示例

    python多线程定时器

    总结起来,`python多线程定时器`的实现涉及到Python的`threading`和`time`模块,通过`Thread`和`Timer`类来创建和管理线程,使用定时器控制线程的启动时间。主程序`main.py`使用这些工具来安排多个任务按设定的间隔...

    python多线程池离线安装包.zip

    本离线安装包“python多线程池离线安装包.zip”包含了实现Python多线程所需的关键组件。主要包含以下三个子文件: 1. `pip-19.2.3.tar.gz`:这是Python的包管理器pip的一个版本,用于安装和管理Python库。在离线...

    python多线程爬虫爬取电影天堂资源

    Python多线程爬虫爬取电影天堂资源是一个实用且具有挑战的项目。以下是对该项目的详细说明: 1. 项目概述: 该项目旨在使用Python编写一个多线程爬虫程序,从电影天堂网站上爬取电影资源信息,包括电影名称、年份、类型...

    python多线程压测demo

    python多线程压测demo

    Python多线程编程(6寸)[归纳].pdf

    Python多线程编程是利用Python实现程序并行性的一种方式,尤其适合于处理异步、并发事务和资源密集型任务。在多线程环境中,多个线程可以同时执行,提高程序效率,尤其对于那些需要从多个输入源处理数据或者进行大量...

    PYthon-multithreading-Test.rar_python_python 多线程_python多线程_多线程

    本压缩包“PYthon-multithreading-Test.rar”包含了有关Python多线程测试的源码,旨在帮助用户深入理解和实践Python的线程操作。 Python中的多线程是通过`threading`模块实现的,这个模块提供了基本的线程和同步...

    探寻python多线程ctrl+c退出问题解决方案

    经常会遇到下述问题:很多io busy的应用采取多线程的方式来解决,但这时候会发现python命令行不响应ctrl-c 了,而对应的java代码则没有问题: 复制代码 代码如下: public class Test {   public static void main...

    浅析Python多线程与多进程的使用

    在多线程编程中,我们需要注意全局解释器锁(GIL),它是Python解释器为了保证线程安全而引入的一个机制,但同时也限制了多线程在CPU密集型任务中的性能,因为GIL使得Python在同一时刻只能有一个线程在执行。...

    python多线程Python多线程学习Python中的线程使用

    python,python多线程Python多线程学习Python中的线程使用python多线程Python多线程学习Python中的线程使用

    10个线程的Python多线程爬虫(采集新浪数据).rar

    一个Python多线程爬虫,在工作时,开10个线程来抓取新浪网页的数据,抓取并保存页面, 并且根据deep返回页面链接,根据key确定是否保存该页面,其中:  deep == 0时,是抓取的最后一层深度,即只抓取并保存页面,不...

    深入理解Python 多线程

    Python里的多线程是假的多线程,不管有多少核,同一时间只能在一个核中进行操作!利用Python的多线程,只是利用CPU上下文切换的优势,看上去像是并发,其实只是个单线程,所以说他是假的单线程。 那么什么时候用多...

    python 多线程脚本

    python 多线程封装脚本,可以直接拿来当lib导入使用。

    单线程与多线程python爬虫地图瓦片源码

    本文将深入探讨“单线程与多线程Python爬虫地图瓦片源码”的相关知识点。 首先,我们需要理解“线程”这一概念。线程是程序执行的最小单元,每个线程负责执行特定的任务。在单线程环境中,程序按顺序执行,一次只能...

    python多线程,断点续传下载程序

    python多线程,断点续传下载程序,功能比较简单,可以进行二次开发。实现更好用的 功能。

    Python多线程编程

    Python多线程编程文档说明 多进程编程 一、 multiprocessing 模块 1. multiprocessing 模块提供了多进程编程的能力 它的API非常类似于 threading 模块,但是也提供了一些threading 模块不具有的能力 相比于线程,它...

Global site tag (gtag.js) - Google Analytics