Skip to content

解决issue 906,完成对银行任务代码编写 #1039

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions Day61-65/63.Python中的并发编程-1.md
Original file line number Diff line number Diff line change
@@ -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 代码也没有机会真正并行的执行。
42 changes: 42 additions & 0 deletions Day61-65/allocation.py
Original file line number Diff line number Diff line change
@@ -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()
32 changes: 32 additions & 0 deletions Day61-65/formal.py
Original file line number Diff line number Diff line change
@@ -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()