Python使用 - 多线程

常见术语及用法

 

基本使用

# 定义线程类
class MyThread(threading.Thread):
    def __init__(self):
        super(MyThread, self).__init__() # 或 threading.Thread.__init__(self)

    def run(self) -> None:
        tid = threading.currentThread().ident
        tname = threading.currentThread().getName()
        print("===== 线程开始: id: %d, name: %s" % (tid, tname))
        # 线程休眠
        time.sleep(5)
        print("===== 线程结束: id: %d, name: %s" % (tid, tname))

 
print("主线程: id: %d, name: %s" % (threading.currentThread().ident, threading.currentThread().name))

# 创建线程
thread1 = MyThread()
# 启动线程
thread1.start()
# 主线程等待thread1线程结束
thread1.join()

print("主线程退出")

 

线程同步:锁

多个人从苹果箱子里取苹果吃,一次只能取一个

import threading
import time


class AppleBox:
    def __init__(self, apple_num: int):
        self.apple_num = apple_num
        self.res_lock = threading.Lock()

    def get(self):
        self.res_lock.acquire()

        t_apple_no = -1
        if self.apple_num > 0:
            t_apple_no = self.apple_num
            self.apple_num -= 1

        self.res_lock.release()
        return t_apple_no


class MyThread(threading.Thread):
    def __init__(self, apple_box: AppleBox):
        super(MyThread, self).__init__() # 或 threading.Thread.__init__(self)
        self.apple_box = apple_box

    def run(self) -> None:
        tid = threading.currentThread().ident
        tname = threading.currentThread().getName()

        for i in range(20):
            # print("===== %s(%d) 尝试从箱子里拿苹果\n" % (tname, tid))
            apple_no = self.apple_box.get()
            if apple_no < 0:
                print("===== %s(%d) 苹果拿完了\n" % (tname, tid))
                return

            print("===== %s(%d) 拿到了%s号苹果, 走到边上开始吃苹果\n" % (tname, tid, apple_no))
            time.sleep(3)
            # print("===== %s(%d) 吃完%s号苹果\n" % (tname, tid, apple_no))


apple_box = AppleBox(15)
thread_list = []
for i in range(5):
    # 创建线程
    thread1 = MyThread(apple_box)
    # 启动线程
    thread1.start()
    thread_list.append(thread1)

# 主线程等待上面的线程执行完毕
for t in thread_list:
    t.join()

print("退出主线程")

 

线程同步:锁+线程间通信

上面吃苹果的例子情况比较简单,访问共享资源的条件是:有人在访问的话就等待;

现在访问共享资源的条件增加了,1、有人在访问的话要等,2、如果资源是空或满的的要等;

仅仅用锁的方式:

# 共享资源
class Products:
    def __init__(self, max_num: int):
        self.num = 0
        self.producing_num = 0
        self.max_num = max_num
        self.res_lock = threading.Lock()
        self.cond_empty = threading.Condition(self.res_lock) # 产品被消耗完时, 消费者等待
        self.cond_full = threading.Condition(self.res_lock) # 库存满时, 生产者等待

    def take(self):
        tid = threading.currentThread().ident
        tname = threading.currentThread().getName()

        self.res_lock.acquire() # self.cond_empty.acquire()
        while self.num <= 0:
            print("%s: 没有产品, 等待3s" % (tname))
            self.res_lock.release()
            time.sleep(3)
            self.res_lock.acquire()
            print("%s: 3s到了, 检查是否有产品" % (tname))

        self.num -= 1
        print("%s: 消耗了1个产品,当前总共%s" % (tname, self.num))
        self.res_lock.release() # self.cond_empty.release()

        # 模拟消耗耗时, 物品是立即拿走的, 然后到边上去消耗, 而不是在仓库里消耗
        time.sleep(10 + random.random())


    def put(self):
        tid = threading.currentThread().ident
        tname = threading.currentThread().getName()

        self.res_lock.acquire()
        while (self.num + self.producing_num) >= self.max_num:
            print("%s: 库存满了, 等待3s, %s个生产中" % (tname, self.producing_num))
            self.res_lock.release()
            time.sleep(3)
            self.res_lock.acquire()
            print("%s: 3s到了, 检查库存是否满" % (tname))

        self.producing_num += 1
        self.res_lock.release()

        # 模拟生产耗时, 要生产出来了物品数量才能+1
        time.sleep(5 + random.random())

        self.res_lock.acquire()
        self.producing_num -= 1
        self.num += 1
        print("%s: 生产了1个产品,当前总共%s" % (tname, self.num))
        self.res_lock.release()

也可以做,但是效率会相对较低,因为需要不断的去轮询检查是不是空或者满了。

 

用线程间通信的方式

# 共享资源
class Products:
    def __init__(self, max_num: int):
        self.num = 0
        self.producing_num = 0
        self.max_num = max_num
        self.res_lock = threading.Lock()
        self.cond_empty = threading.Condition(self.res_lock) # 产品被消耗完时, 消费者等待
        self.cond_full = threading.Condition(self.res_lock) # 库存满时, 生产者等待

    def take(self):
        tid = threading.currentThread().ident
        tname = threading.currentThread().getName()

        self.res_lock.acquire() # self.cond_empty.acquire()
        while self.num <= 0:
            print("%s: 没有产品, 等待" % (tname))
            self.cond_empty.wait()
            print("%s: 消费者被唤醒,检查是否有产品" % (tname))

        self.num -= 1
        print("%s: 消耗1个产品,当前总共%s,通知生产者" % (tname, self.num))
        # 产品被消耗了, 腾出了库存空间, 通知生产者
        self.cond_full.notify_all()
        self.res_lock.release() # self.cond_empty.release()

        # 模拟消耗耗时, 物品是立即拿走的, 然后到边上去消耗, 而不是在仓库里消耗
        time.sleep(10 + random.random())

def put(self): tid = threading.currentThread().ident tname = threading.currentThread().getName() self.res_lock.acquire() while (self.num + self.producing_num) >= self.max_num: print("%s: 库存满了, 等待, %s个生产中" % (tname, self.producing_num)) self.cond_full.wait() print("%s: 生产者被唤醒,检查库存是否满" % (tname)) self.producing_num += 1 self.res_lock.release() # 模拟生产耗时, 要生产出来了物品数量才能+1 time.sleep(5 + random.random()) self.res_lock.acquire() self.producing_num -= 1 self.num += 1 print("%s: 生产了1个产品,当前总共%s,通知消费者" % (tname, self.num)) # 有产品了, 通知消费者 self.cond_empty.notify_all() self.res_lock.release()

 

生产者,消费者

class Producer(threading.Thread):
    def __init__(self, products):
        super(Producer, self).__init__() # 或 threading.Thread.__init__(self)
        self.products = products

    def run(self) -> None:
        for i in range(10):
        self.products.put()


class Consumer(threading.Thread):
    def __init__(self, products):
        super(Consumer, self).__init__()
        self.products = products

    def run(self) -> None:
        for i in range(10):
        self.products.take()


products = Products(5)

producer1 = Producer(products)
producer2 = Producer(products)
producer1.start()
producer2.start()

consumer1 = Consumer(products)
consumer2 = Consumer(products)
consumer1.start()
consumer2.start()

producer1.join()
producer2.join()

consumer1.join()
consumer2.join()

print("退出主线程")

 

java中有,Python中还没看到的:

守护线程

线程池

Priority线程优先级 

 

参考
Java并发编程基础:线程与同步 - 知乎 (zhihu.com)

走进并发,线程同步与线程通信全解析 - 知乎 (zhihu.com)

Java 生产者和消费者3种实现方式_用java实现生产者消费者_小博要变强啊~的博客-CSDN博客

 

posted @ 2023-08-01 23:22  yanghui01  阅读(11)  评论(0编辑  收藏  举报