python学习笔记-多线程

#============================多线程=========================
# 参看文档
# https://www.cnblogs.com/jokerbj/p/7460260.html
# http://www.dabeaz.com/python/UnderstandingGIL.pdf

##=================多线程、多进程、全局解释器的区别============
# 进程: 程序运行的一个状态
    # 包含地址空间,内存,数据栈等
    # 每个进程由自己完全独立的运行环境,多进程共享数据是一个问题
# 线程
  # 一个进程的独立运行片段,一个进程可以由多个线程
  # 轻量化的进程
  # 一个进程的多个现成间共享数据和上下文运行环境
  # 共享互斥问题
# 全局解释器锁(GIL)
  # Python代码的执行是由python虚拟机进行控制
  # 在主循环中只能有一个控制线程执行
  
#=================多线程使用1:_thread模块=================
  # thread:有问题,不好用,python3改成了_thread
  # 使用_thread启动多线程
  # 启动多线程函数为start_new_thead
  # 参数两个,一个是需要运行的函数名,第二是函数的参数作为元祖使用,为空则使用空元祖
  # 注意:如果函数只有一个参数,需要参数后由一个逗号

    import _thread as thread
    
    def loop1(in1):
        pass
    
    def loop2(in1, in2):
        pass
    
    def main():
      thread.start_new_thread(loop1, ("in1", ))
      thread.start_new_thread(loop2, ("in1", "in2"))
  
  if __name__ == '__main__':
    main()
    # 一定要有while语句
    # 因为启动多线程后本程序就作为主线程存在
    # 如果主线程执行完毕,则子线程可能也需要终止
    while True:    #使主进程永远不停止
        time.sleep(1)    
    

#=================多线程使用2:threading=================
    #直接利用threading.Thread生成Thread实例
    #1. t = threading.Thread(target=xxx, args=(xxx,))
    #2. t.start():启动多线程
    #3. t.join(): 等待多线程执行完成

    import threading
    
    def loop1(in1):
        pass
    
    def loop2(in1, in2):
        pass
    
    def main():
        t1 = threading.Thread(target=loop1, args=("in1",))

    # 守护线程daemon
      # 如果在程序中将子线程设置成守护线程,则子线程会在主线程结束的时候自动退出
      # 一般认为,守护线程不中要或者不允许离开主线程独立运行
      # 守护线程案例能否有效果跟环境相关
      # 守护守护线程的方法,必须在start之前设置,否则无效
        t1.setDaemon(True) # 或t1.daemon = True

        t1.setName("THR_1") # 给线程设置名字
        t1.start()

        t2 = threading.Thread(target=loop2, args=("in1", "in2"))
        t2.start()
    
      # 线程常用属性
        for thr in threading.enumerate(): # 返回一个包含正在运行的线程的list,正在运行的线程指的是线程启动后,结束前的状态
             print("正在运行的线程名字是: {0}".format(thr.getName()))  # 得到线程的名字
             print("正在运行的子线程数量为: {0}".format(threading.activeCount())) # 返回正在运行的线程数量,同 len(threading.enumerate)
             print(threading.currentThread())  # 返回当前线程变量 
       
        t1.join()
        t2.join()
  
  if __name__ == '__main__':
        main()

  


#=================多线程使用3:继承threading.Thread=================
  # 直接继承Thread
  # 重写run函数
  # 类实例可以直接运行

    import threading
    import time

    # 1. 类需要继承自threading.Thread
    class MyThread(threading.Thread):
    def __init__(self, arg):
        super(MyThread, self).__init__()
        self.arg = arg

    # 2 必须重写run函数,run函数代表的是真正执行的功能
    def  run(self):
        time.sleep(2)
        print("The args for this class is {0}".format(self.arg))

    for i in range(5):
    t = MyThread(i)
    t.start()
    t.join()
    print("Main thread is done!!!!!!!!")

    #工业化实例:

    import threading
    from time import sleep, ctime

    loop = [4,2]

    class ThreadFunc:

        def __init__(self, name):
            self.name = name

        def loop(self, nloop, nsec):
            '''
            :param nloop: loop函数的名称
            :param nsec: 系统休眠时间
            :return:
            '''
            print('Start loop ', nloop, 'at ', ctime())
            sleep(nsec)
            print('Done loop ', nloop, ' at ', ctime())

    def main():
        print("Starting at: ", ctime())

        # ThreadFunc("loop").loop 跟一下两个式子相等:
        # t = ThreadFunc("loop")
        # t.loop
        # 以下t1 和  t2的定义方式相等
        t = ThreadFunc("loop")
        t1 = threading.Thread(target=t.loop, args=("LOOP1", 4))
        # 下面这种写法更西方人,工业化一点
        t2 = threading.Thread(target=ThreadFunc('loop').loop, args=("LOOP2", 2))

        # 常见错误写法
        #t1 = threading.Thread(target=ThreadFunc('loop').loop(100,4))
        #t2 = threading.Thread(target=ThreadFunc('loop').loop(100,2))

        t1.start()
        t2.start()

        t1.join( )
        t2.join()

        print("ALL done at: ", ctime())

    if __name__ == '__main__':
        main()

  #====================================共享变量=====================================
  # 当多个现成同时访问一个变量的时候,会产生共享变量的问题
  # 解决变量:锁,信号灯,
  # 锁(Lock):是一个标志,表示一个线程在占用一些资源

    lock = threading.Lock()
    lock.acquire()  # 上锁,申请锁
    pass
    lock.release()  # 释放锁

  # 线程安全问题:
    # 线程安全:如果一个资源/变量,对于多线程,不加锁也不会引起任何问题
    # 线程不安全变量类型: list, set, dict
    # 线程安全变量类型: queue
    
  # 生产者消费者问题
    # 一个模型,可以用来搭建消息队列, 
    # queue是一个用来存放变量的数据结构,特点是先进先出,内部元素排队,可以理解成一个特殊的list

    import queue
    q = queue.Queue()
    q.put("ID1")
    q.put("ID2")
    q.get() #ID1
    q.get() #ID2

  # 死锁问题
  # 锁的等待时间问题,示例片段:

  lock = threading.Lock()
  lock.acquire(timeout=4)  # 申请锁,等待4秒继续
  pass
  rst = lock.acquire(timeout=2)
  if rst:
        lock.release()
  else:
        print("未申请到lock.....")
    

  # semphore允许一个资源最多由多个多线程同时使用,示例:

    import threading
    import time

    # 参数定义最多几个线程同时使用资源    
    sem = threading.Semaphore(3) 
    def func():
      if semaphore.acquire():
        for i in range(5):
            print(threading.currentThread().getName() + ' get semaphore')
        time.sleep(15)
        semaphore.release()
        print(threading.currentThread().getName() + ' release semaphore')

    for i in range(8):
    t1 = threading.Thread(target=func)
    t1.start()

    # threading.Timer是利用多线程,在指定时间后启动一个功能
    t = threading.Timer(6, func)
      
    # 可重入锁:一个锁,可被一个线程多次申请
    # 主要解决递归调用的时候,需要申请锁的情况
    t = threading.RLock()

#======================多线程替代方案======================
# subprocess
    # 完全跳过线程,使用进程
    # 是派生进程的主要替代方案
    # python2.4后引入
# multiprocessiong
    # 使用threadiing接口派生,使用子进程
    # 允许为多核或者多cpu派生进程,接口跟threading非常相似
    # python2.6
# concurrent.futures
    # 新的异步执行模块
    # 任务级别的操作
    # python3.2后引入
    
# 多进程
# 进程间通讯(InterprocessCommunication, IPC )
# 进程之间无任何共享状态

# 多进程的创建
  #方法1、直接生成Process实例对象

  import multiprocessing
    p = multiprocessing.Process(target = clock, args = (5,))
  p.start()

  #方法2、派生子类
 

 import multiprocessing
  class ClockProcess(multiprocessing.Process):
    def __init__(self, interval):
    super().__init__()
    self.interval = interval

      def run(self):
      while True:
          print("The time is %s" % ctime())
          sleep(self.interval)
  
  c = ClockProcess(3)
  c.start()

# 在os中查看pid,ppid以及他们的关系              

  import os
  os.getpid() # 父进程
  os.getppid() # 本身进程

# JoinableQueue,参见生产者消费者模型,示例片段:

import multiprocessing
from time import ctime

def consumer(input_q):
    print("Into consumer:", ctime())
    while True:
        item = input_q.get()
        if item is None:
            break
        print("pull", item, "out of q")
    print ("Out of consumer:", ctime()) ## 此句执行完成,再转入主进程

def producer(sequence, output_q):
    print ("Into procuder:", ctime())
    for item in sequence:
        output_q.put(item)
        print ("put", item, "into q")
    print ("Out of procuder:", ctime())

if __name__ == '__main__':
    q = multiprocessing.Queue()
    cons_p = multiprocessing.Process(target = consumer, args = (q,))
    cons_p.start()
  # 生产多个项,sequence代表要发送给消费者的项序列
  # 在实践中,这可能是生成器的输出或通过一些其他方式生产出来
    sequence = [1,2,3,4]
    producer(sequence, q)

  #设置哨兵;
  #如果启动多个消费者进程,则调用多条q.put(None),与消费者进程数一样。
    q.put(None)
    # 等待所有项被处理
    cons_p.join()

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值