Async Techniques and Examples in Python Transcripts
Chapter: Thread safety
Lecture: Demo: An unsafe bank
Login or
purchase this course
to watch this video and the rest of the course contents.
0:00
Welcome to our next set of demos. So we're going to have two or three different sets of programs we're going to go through. We have an unsafe bank
0:09
which you should never, ever put your money in the unsafe bank. It may lose your money. Trust me this is bad.
0:14
And we have this thing I've called a safe bank. Now the safe bank starts out unsafe. Our job is to take the unsafe bank and make it safe.
0:23
How do we know it's unsafe? Well let's go and see what it does and we'll talk about it. So down here we have our main method.
0:29
Well, first of all we have different accounts. They're extremely simple. They don't have to keep track of much. So we just have a balance right?
0:36
In reality they have owners and numbers and things like that but ours just has a balance. And so we're going to create a bunch of accounts
0:45
and we're going to figure out what the total number is in these accounts. The total value of these accounts and then
0:50
we're going to go about transferring money between them. One of the mathematical properties that should always
0:56
be true if we're taking money from one account and putting it into the other all within the same bank no matter how many accounts are there, the number
1:04
the overall total should always be the same. Now that's excluding real things like fees and external banks and stuff like that but
1:12
this is a simple bank. What we should be able to see is at no time will we ever not have a total amount whatever that total turns out to be
1:21
of money in the overall bank if we look at all the accounts, yeah? And that's what validate_bank() does here.
1:29
So we'll go look at that. Now we're going to kick off what is that, five threads? Going to kick off a bunch of threads
1:33
and they're all going to run this do_bank_stuff() they're all going to have the accounts. I'm going to pass the total so they can do a little check
1:40
to see if the bank is still valid. We're going to kick them all off and then we're going to wait for them to finish. That's standard stuff.
1:47
We talked about that before. Now down here in do_bank_stuff() we're just going to go for 10,000 times around.
1:55
We're going to randomly get two different accounts. We're going to create a random amount between one and $100.
2:02
We're going to transfer money between them and we're going to validate that it's fine. So let's look at that transfer
2:08
that's probably the last thing to do. So to transfer, super easy. We're given a from account to take the money from
2:16
a to account to put the money in and how much to do. Add a little error checking in the top and then we just go take the money out of the top one
2:24
and put it into the to account. Take it out of the from, put it into the to. And then just to simulate some real activity right
2:32
something other than Python's GIL not really lettin' us do anything we're going to say, let's just give up our current time slice.
2:40
We're not even sleeping for one millisecond but just imagine that this operation that we're trying to do here, this do transfer
2:48
takes one millisecond right? It's just a little, tiny bit of time that is going to be the key to all sorts of problems.
2:55
It just means these problems are going to be more observable but it doesn't actually mean the problem would go away if I were to comment that line out.
3:03
Okay finally, final thing is we're going to say validate_bank(). That is just to sum up the current balance and see
3:09
if the current is the total and things like that. So if the current and the total ever differ we've got something wrong right?
3:17
That's a property of our bank we should always have the same money if we're just shifting around accounts. Whew, well that's the introduction.
3:24
You want to run it and see what happens? Let's kick off these five threads that are each going to do 10,000 requests across balance transfers
3:32
between these various accounts and we'll see how it works. We're going to run safe bank. Alright so let's kick that off. Huh, what do you think?
3:42
Well first of all, let's imagine we didn't do that. Let's put this away for one second. Let's imagine it's single-threaded.
3:48
How does it work? We're starting transfers everything was good in the beginning did a bunch of transfers, was good in the end.
3:55
That's how it should work all of the time but this is not thread-safe and I have set it up to be pretty likely to hit that error actually.
4:04
If we run it now though you can see what's happening. One of these, let's say this thread is comin' along and transferring money
4:13
from account A to account B. It's halfway through so it's taken money out of A but not in B. This one just finished a transfer and calls validate.
4:20
It sees the invalid state that the first thread on line 21 has created, and it shoots out an error oh my gosh warning warning warning.
4:28
Eventually the top thread here puts it back into a valid state but this is not good okay? So here you can see tons and tons of errors in this bank
4:40
like look at that scroll bar. That is bad news bears right there. But at the end everything is fine, no problem. It's just a matter of
4:46
did you observe that invalid state or not? And it turns out because so much stuff is happening you're observing it a whole lot.
4:54
Would you like to put your money in this bank? It's called safe bank but it is nowhere near safe, yet.
5:00
So our goal will be to use the various constructs in Python to make it safe.