zoukankan      html  css  js  c++  java
  • [b0032] python 归纳 (十七)_线程同步_信号量Semaphore

    代码:

    # -*- coding: utf-8 -*-
    """
    多线程并发同步 ,使用信号量threading.Semaphore
    
    逻辑:
        多个线程,对同一个共享变量 ,加1,并且各自打印加1前、加1后的值
    总结:
    信号量也提供acquire方法和release方法,每当调用acquire方法的时候,如果内部计数器大于0,则将其减1,
    如果内部计数器等于0,则会阻塞该线程,知道有线程调用了release方法将内部计数器更新到大于1位置
    
        1. 个人感觉,信号量类似锁,创建2个大小的信号量,类似创建2把锁
        2. 信号量好像可以实现进程Pool,做到任何时候最多有多少个线程执行某些逻辑
        3.  使用 信号量,要很小心,可能存在多个线程操作同一份数据 ,导致不一致
         比如 case1,case2,case3,case4
    
    使用:
        1. 创建指定大小的信号量对象  sem = threading.Semaphore(value=2)
        2. 在必要的地方获得信号量,一般是操作共享数据  sem.acquire()
        3. 结束的地方,及时释放信号量  sem.release()
    参考:
    
    """
    import threading
    import time
    
    # 计算pi
    def calc_pi():
        from sys import stdout
        scale = 10000
        maxarr = 2800
        arrinit = 2000
        carry = 0
        arr = [arrinit] * (maxarr + 1)
        for i in xrange(maxarr, 1, -14):
          total = 0
          for j in xrange(i, 0,-1):
            total = (total * j) + (scale * arr[j])
            arr[j] = total % ((j * 2) - 1)
            total = total / ((j * 2) - 1)
          # stdout.write("%04d" % (carry + (total / scale)))
          carry = total % scale
    
    # 打印一个字符
    def show1():
        print "h"
    
    # 打印很多字符
    def show2():
        print "hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh"
    
    class Num:
        """
        多线程操作的共享数据和方法封装
        数据 num
        方法 add 加1
        """
        def __init__(self):
            self.num = 0
            self.sem = threading.Semaphore(value=2)  # 大小=2的信号量
    
        def add(self):
            self.sem.acquire() # 获取信号量, 内部计数器-1
            begin = self.num   # 加1前的值
            self.num += 1
    
            # time.sleep(1)  # case1 睡眠1秒
            # calc_pi()      # case2 执行计算密集型运行
            # show1()        # case3 打印很少字符
            # show2()        # case4 打印很多字符
    
            end = self.num   # 加1后的值
            time.sleep(2)    # 各个线程睡眠2秒,方便看程序执行效果
            self.sem.release() # 释放信号量,内部计数器+1
    
            return (begin,end)
    
    # 共享数据
    n = Num()
    
    class jdThread(threading.Thread):
        """多线程代码,对共享数据加1,并且打印
        """
        def __init__(self,item):
            threading.Thread.__init__(self)
            self.item = item
    
        def run(self):
            value = n.add()    # 加1,拿到返回值 (处理前,处理后)
            print "
    ", time.strftime('%M:%S',time.localtime(time.time())), " "+str(value[0])+"->"+str(value[1])+" "
    
    
    if __name__ == "__main__":
    
        # 启动20个线程
        for item in range(20):
            t = jdThread(item)
            t.start()
    
        print "main end"

    输出:

    基准,以上代码执行

    main end
    
    03:58  0->1 
    
    03:58  1->2 
    
    04:00  2->3 
    
    04:00  3->4 
    
    04:02  4->5 
    
    04:02  5->6 
    
    04:04  6->7 
    
    04:04  7->8 
    
    04:06  8->9 
    
    04:06  9->10 
    
    04:08  10->11 
    
    04:08  11->12 
    
    04:10  12->13 
    
    04:10  13->14 
    
    04:12  14->15 
    
    04:12  15->16 
    
    04:14  16->17 
    
    04:14  17->18 
    
    04:16  18->19 
    
    04:16  19->20 
    View Code

    case1,多执行case1

    main end
    
    07:48
     07:48 1->2  
     0->2 
    
    07:51 
     2->4 07:51
      3->4 
    
    07:54 
     4->6 07:54
      5->6 
    
    07:57  6->8 
    
    07:57  7->8 
    View Code

    case2

    main end
    
    
    08:1808:18   0->2  1->2 
    
    
    08:21  3->4 
    
    08:21  2->4 
    
    08:23  5->6 
    
     08:23  4->6 
    
    08:26  7->8 
    
    08:26  6->8 
    View Code

    case3

    h
    h
    main end
    
    08:48h 
     0->1 
    h
    
    08:48  1->2 
    
    h08:50
      2->3 
    
    08:50 h 3->4 
    
    
    08:52h 
     4->5 
    h
    
    08:52  5->6 
    
    h08:54
      6->7 
    
    08:54 h 7->8 
    
    
    h08:56
      8->9 
    h
    
    08:56  9->10 
    
    08:58 h 10->11 
    
    
    08:58h 
     11->12 
    
    09:00h 
     12->13 
    
    09:00  13->14 
    h
    h
    09:02
      14->15 
    
    09:02 h 15->16 
    
    
    h09:04
      16->17 
    
    09:04 h 17->18 
    
    
    09:06  18->19 
    
    09:06  19->20 
    
    Process finished with exit code 0
    View Code

    case4

    D:ProgramsAnacondapython.exe D:/1_practice/python/projects/downloads_modify/归类/并发/thread_sync_2.py
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    main end
    
    10:55 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 1->2 
    
    
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh10:55
      0->1 
    
    10:57hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 
      2->3 
    
     10:57hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 
     3->4 
    
    10:59  4->5 
    
     hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh10:59hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 
    
     5->6 
    
    11:01 
     7->8 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
     11:01
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 
     6->8 
    
    11:03  8->10 
     
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh11:03hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
     
     9->10 
    
    11:05 
     11->12 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh11:05
      
    hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 10->12 
    
    
    11:07
     11:07 12->14 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 
     
     13->14 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh
    
    
    11:09 hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh 14->16 
    
    
    11:09hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhhh  15->16 
    View Code

    输出说明 :

    基准输出 , 执行正常的逻辑,每隔2秒执行2个线程,分布对共享变量加1,逻辑正常

    case1  睡眠1秒 ,  被其他线程 修改了 数据

    case2    计算 密集型,同case1

    case3   输出少了 字符 , 逻辑正常

    case4   输出大量字符  ,通case1

  • 相关阅读:
    iptables防火墙-SNAT和DNAT
    exists & in
    系统演化之路
    promethue 采集traefik指标列表
    Grafana中变量
    Wireshark抓包
    http协议格式 基于ABNF语义定义
    Prometheus 管理常用知识点
    python时间转换
    通过salt-api获取minion的ip地址
  • 原文地址:https://www.cnblogs.com/sunzebo/p/9630471.html
Copyright © 2011-2022 走看看