python之多线程(二)

共享变量

- 概念: 当多个线程同时访问一个变量的时候,会产生共享变量的问题 

# 不启用多线程,正常执行结果
import threading

sum = 0
loopSum = 100000


def myAdd():
    global sum, loopSum
    for i in range(1, loopSum):
        sum += 1


def myMinu():
    global sum, loopSum
    for i in range(1, loopSum):
        sum -= 1


if __name__ == '__main__':
    myAdd()
    print(sum)
    myMinu()
    print(sum)
99999
0
# 多线程执行两个方法

import threading

sum = 0
loopSum = 100000


def myAdd():
    global sum, loopSum
    for i in range(1, loopSum):
        sum += 1


def myMinu():
    global sum, loopSum
    for i in range(1, loopSum):
        sum -= 1


if __name__ == '__main__':
    print("Stating ....{0}".format(sum))
    # 启用多线程实例,查看执行结果
    t1 = threading.Thread(target=myAdd, args=())
    t2 = threading.Thread(target=myMinu, args=())
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("Done .... {0}".format(sum))
Stating ....0
Done .... -31331

解决方案: 锁, 

  • 锁(LOCK): 
    • 是一个标志,表示一个线程在占用一些资源
    • 使用方法: 
      • 上锁
      • 使用共享资源
      • 释放锁
    • 琐谁: 
      • 那个资源需要多线程共享,锁那个
    • 理解锁: 
      • 锁其实是一个令牌,并且这个令牌只有一个,访问共享资源时需要去申请这个令牌,只有申请到令牌的线程才能操作共享资源,操作完成后,需将令牌归还
import threading

sum = 0
loopSum = 100000
# 定义锁
lock = threading.Lock()


def myAdd():
    global sum, loopSum
    for i in range(1, loopSum):
        # 加锁,申请锁
        lock.acquire()
        sum += 1
        # 释放锁
        lock.release()


def myMinu():
    global sum, loopSum
    for i in range(1, loopSum):
        # 加锁,申请锁
        lock.acquire()
        sum -= 1
        # 释放锁
        lock.release()


if __name__ == '__main__':
    print("Stating ....{0}".format(sum))
    # 启用多线程实例,查看执行结果
    t1 = threading.Thread(target=myAdd, args=())
    t2 = threading.Thread(target=myMinu, args=())
    t1.start()
    t2.start()
    t1.join()
    t2.join()
    print("Done .... {0}".format(sum))
Stating ....0
Done .... 0

 线程安全问题: 
- 如果一个资源/变量,它对于多线程来讲,不用加锁也不会引起任何问题,则称为线程安全。 
- 线程不安全变量类型:list,set,dict 
- 线程安全变量类型:queue 

  • 生产者消费者问题 
    • 一个模型,用来搭建消息队列
    • queue 是一个用来存放变量的数据结构,特点是先进先出,内部元素排队,可以理解成一个特殊的list

 

import threading
import time
import queue


# python2
# from Queue import Queue

# python3
class Produer(threading.Thread):
    def run(self):
        global queue
        count = 0
        while True:
            if queue.qsize() < 1000:
                for i in range(100):
                    count = count + 1
                    msg = "生成产品" + str(count)
                    queue.put(msg)
                    print(msg)
            time.sleep(0.5)


class Consumer(threading.Thread):
    def run(self):
        global queue
        while True:
            if queue.qsize() > 100:
                for i in range(3):
                    msg = self.name + "消费了" + queue.get()
                    print(msg)
            time.sleep(1)


if __name__ == "__main__":
    queue = queue.Queue()
    for i in range(500):
        queue.put("初始产品:"+str(i))
    for i in range(2):
        p = Produer()
        p.start()
    for i in range(5):
        c = Consumer()
        c.start()

死锁

import threading
import time

lock_1 = threading.Lock()
lock_2 = threading.Lock()

def funca():
    print("A 函数启动....")
    print("A 申请了锁1...")
    lock_1.acquire()
    print("A 等待申请锁2...")
    time.sleep(2)
    lock_2.acquire()
    print("A 释放了锁2...")
    lock_2.release()
    print("A 释放了锁1")
    lock_1.release()
    print("A 函数执行结束...")


def funcb():
    print("B 函数启动...")
    print("B 函数申请锁2...")
    lock_2.acquire()
    print("B 函数等待申请锁1...")
    time.sleep(4)
    print("B 函数申请申请锁1...")
    lock_1.acquire()

    print("B 函数释放锁1...")
    lock_1.release()
    print("B 函数释放锁2...")
    lock_2.release()
    print("B 函数执行结束...")


if __name__ == '__main__':
    t1 = threading.Thread(target=funca, args=())
    t2 = threading.Thread(target=funcb, args=())
    t1.start()
    t2.start()
    t1.join()
    t2.join()
  • 锁的等待时间
import threading
import time

lock_1 = threading.Lock()
lock_2 = threading.Lock()


def funca():
    print("A 函数启动....")
    print("A 申请了锁1...")
    lock_1.acquire(timeout=4)
    print("A 等待申请锁2...")
    time.sleep(2)
    res = lock_2.acquire(timeout=2)
    if res:
        print("A 得到了锁2...")
        lock_2.release()
        print("A 释放了锁2...")
    else:
        print("A 没有申请到锁2...")
    print("A 释放了锁1")
    lock_1.release()
    print("A 函数执行结束...")


def funcb():
    print("B 函数启动...")
    print("B 函数申请锁2...")
    lock_2.acquire()
    print("B 函数等待申请锁1...")
    time.sleep(4)
    print("B 函数申请申请锁1...")
    lock_1.acquire()

    print("B 函数释放锁1...")
    lock_1.release()
    print("B 函数释放锁2...")
    lock_2.release()
    print("B 函数执行结束...")


if __name__ == '__main__':
    t1 = threading.Thread(target=funca, args=())
    t2 = threading.Thread(target=funcb, args=())
    t1.start()
    t2.start()
    t1.join()
    t2.join()
  • semphore 
    - 允许一个资源最多由几个线程同时使用
import threading
import time

# 参数定义同一个资源最多几个线程同时使用

semphore = threading.Semaphore(3)


def func():
    if semphore.acquire():
        for i in range(5):
            print(threading.currentThread().getName() + "get semphore")
            time.sleep(15)
            semphore.release()
            print(threading.currentThread().getName() + "release semphore")


for i in range(8):
    t1 = threading.Thread(target=func)
    t1.start()
  •  threading.Timer 
    -Timer : 是利用多线程在指定时间后启动一个功能
import threading
import time

def func():
    print("I am body")
    time.sleep(4)
    print("bay")


if __name__ == "__main__":
    t1 = threading.Timer(6, func)
    t1.start()
    i = 0
    while i < 6:
        print("{0}..........".format(i))
        time.sleep(2)
        i += 1
0..........
1..........
2..........
I am body
3..........
4..........
bay
5..........
  •  可重入锁: 
    - 可以被一个线程多次申请 
    - 主要解决递归调用的时候,需要申请锁的情况(递归调用多次申请锁)
import threading
import time

lock = threading.RLock()


class MyThread(threading.Thread):
    def run(self):
        global num
        time.sleep(1)

        if lock.acquire(1):
            num += 1
            msg = self.name + 'set num to ' + str(num)
            print(msg)
            lock.acquire()
            lock.release()
            lock.release()


num = 0

def mytherad():
    for i in range(8):
        t1 = MyThread()
        t1.start()


if __name__ == '__main__':
    mytherad()
Thread-77set num to 1
Thread-78set num to 2
Thread-79set num to 3
Thread-80set num to 4
Thread-81set num to 5
Thread-82set num to 6
Thread-83set num to 7
Thread-84set num to 8

 

发布了36 篇原创文章 · 获赞 24 · 访问量 7万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章