From 75dd526d5c26a3d2790e8c74e7d0398d0c4aadb0 Mon Sep 17 00:00:00 2001 From: breayhing <1519981563@qq.com> Date: Thu, 11 Jul 2024 22:55:35 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=B9=B6=E5=8F=91=E7=BC=96?= =?UTF-8?q?=E7=A8=8B=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...\345\217\221\347\274\226\347\250\213-1.md" | 57 +++++++++++++++++++ Day61-65/allocation.py | 42 ++++++++++++++ Day61-65/formal.py | 32 +++++++++++ 3 files changed, 131 insertions(+) create mode 100644 Day61-65/allocation.py create mode 100644 Day61-65/formal.py diff --git "a/Day61-65/63.Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" "b/Day61-65/63.Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" index d4784fb5a..90669e098 100755 --- "a/Day61-65/63.Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" +++ "b/Day61-65/63.Python\344\270\255\347\232\204\345\271\266\345\217\221\347\274\226\347\250\213-1.md" @@ -374,6 +374,63 @@ if __name__ == '__main__': > **思考**:将上面的代码修改为5个线程向银行账户存钱,5个线程从银行账户取钱,取钱的线程在银行账户余额不足时,需要停下来等待存钱的线程将钱存入后再尝试取钱。这里需要用到线程调度的知识,大家可以自行研究下`threading`模块中的`Condition`类,看看是否能够完成这个任务。 +解答: +```python +import time +from concurrent.futures import ThreadPoolExecutor +from threading import Condition + +class Account(object): + """银行账户""" + + def __init__(self): + self.balance = 0.0 + # 初始化一个Condition对象,用于线程间协调 + self.condition = Condition() + + def deposit(self, money): + # 存钱操作 + with self.condition: + # 更新余额 + new_balance = self.balance + money + time.sleep(0.01) # 模拟延迟 + self.balance = new_balance + # 通知所有等待的线程,存钱操作完成 + self.condition.notify_all() + print(f'Deposited {money}, new balance is {self.balance}') + + def withdraw(self, money): + # 取钱操作 + with self.condition: + # 如果余额不足,等待 + while self.balance < money: + self.condition.wait() # 等待通知 + # 更新余额 + new_balance = self.balance - money + time.sleep(0.01) # 模拟延迟 + self.balance = new_balance + print(f'Withdrew {money}, new balance is {self.balance}') + + +def main(): + """主函数""" + account = Account() + # 使用ThreadPoolExecutor创建一个线程池 + with ThreadPoolExecutor(max_workers=10) as pool: + # 提交5个存钱任务和5个取钱任务 + for _ in range(5): + pool.submit(account.deposit, 1) + pool.submit(account.withdraw, 1) + # 等待所有线程完成 + time.sleep(2) + print(f'Final balance: {account.balance}') + + +if __name__ == '__main__': + main() + +``` + ### GIL问题 如果使用官方的 Python 解释器(通常称之为 CPython)运行 Python 程序,我们并不能通过使用多线程的方式将 CPU 的利用率提升到逼近400%(对于4核 CPU)或逼近800%(对于8核 CPU)这样的水平,因为 CPython 在执行代码时,会受到 GIL(全局解释器锁)的限制。具体的说,CPython 在执行任何代码时,都需要对应的线程先获得 GIL,然后每执行100条(字节码)指令,CPython 就会让获得 GIL 的线程主动释放 GIL,这样别的线程才有机会执行。因为 GIL 的存在,无论你的 CPU 有多少个核,我们编写的 Python 代码也没有机会真正并行的执行。 diff --git a/Day61-65/allocation.py b/Day61-65/allocation.py new file mode 100644 index 000000000..7d5bcfe1e --- /dev/null +++ b/Day61-65/allocation.py @@ -0,0 +1,42 @@ +import time +from concurrent.futures import ThreadPoolExecutor +from threading import Condition, Thread + +class Account(object): + """银行账户""" + + def __init__(self): + self.balance = 0.0 + self.condition = Condition() + + def deposit(self, money): + with self.condition: + new_balance = self.balance + money + time.sleep(0.01) + self.balance = new_balance + self.condition.notify_all() # 通知所有等待的线程 + print(f'Deposited {money}, new balance is {self.balance}') + + def withdraw(self, money): + with self.condition: + while self.balance < money: + self.condition.wait() # 等待通知 + new_balance = self.balance - money + time.sleep(0.01) + self.balance = new_balance + print(f'Withdrew {money}, new balance is {self.balance}') + + +def main(): + """主函数""" + account = Account() + with ThreadPoolExecutor(max_workers=10) as pool: + for _ in range(5): + pool.submit(account.deposit, 1) + pool.submit(account.withdraw, 1) + time.sleep(2) # 等待所有线程完成 + print(f'Final balance: {account.balance}') + + +if __name__ == '__main__': + main() diff --git a/Day61-65/formal.py b/Day61-65/formal.py new file mode 100644 index 000000000..14ce5ffef --- /dev/null +++ b/Day61-65/formal.py @@ -0,0 +1,32 @@ +import time + +from concurrent.futures import ThreadPoolExecutor +from threading import RLock + + +class Account(object): + """银行账户""" + + def __init__(self): + self.balance = 0.0 + self.lock = RLock() + + def deposit(self, money): + # 通过上下文语法获得锁和释放锁 + with self.lock: + new_balance = self.balance + money + time.sleep(0.01) + self.balance = new_balance + + +def main(): + """主函数""" + account = Account() + with ThreadPoolExecutor(max_workers=16) as pool: + for _ in range(100): + pool.submit(account.deposit, 1) + print(account.balance) + + +if __name__ == '__main__': + main() \ No newline at end of file