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.

Talk Python's Mastodon Michael Kennedy's Mastodon