1 00:00:00,539 --> 00:00:03,539 foreign 2 00:00:08,340 --> 00:00:11,660 welcome back everybody 3 00:00:14,400 --> 00:00:19,560 our second speaker in this block this 4 00:00:16,680 --> 00:00:24,300 morning is the inevitable uh inimitable 5 00:00:19,560 --> 00:00:25,080 uh Chris neugebauer indomitable I'm not 6 00:00:24,300 --> 00:00:26,939 sure 7 00:00:25,080 --> 00:00:29,340 unavoidable yes 8 00:00:26,939 --> 00:00:32,700 um he is here today to speak to us about 9 00:00:29,340 --> 00:00:35,160 uh taking a swim in your kitchen sink 10 00:00:32,700 --> 00:00:36,300 while swearing no I'll leave it up to 11 00:00:35,160 --> 00:00:37,739 him to explain what's going on everyone 12 00:00:36,300 --> 00:00:39,300 please welcome Chris nog about at the 13 00:00:37,739 --> 00:00:40,739 stage hello 14 00:00:39,300 --> 00:00:42,660 all right 15 00:00:40,739 --> 00:00:44,520 uh I've never been described as 16 00:00:42,660 --> 00:00:47,520 inevitable before 17 00:00:44,520 --> 00:00:49,200 that is quite a long word given the the 18 00:00:47,520 --> 00:00:50,879 topic of today's talk today we're going 19 00:00:49,200 --> 00:00:52,559 to be talking about five letter words 20 00:00:50,879 --> 00:00:55,140 and I don't know how many letters are 21 00:00:52,559 --> 00:00:57,780 inevitable at the moment 22 00:00:55,140 --> 00:00:59,460 um yeah so uh before I begin uh Wordle 23 00:00:57,780 --> 00:01:01,620 is owned by the New York Times I'm not 24 00:00:59,460 --> 00:01:03,359 from the New York Times uh I will be 25 00:01:01,620 --> 00:01:05,299 using their trademark quite a bit during 26 00:01:03,359 --> 00:01:09,360 this talk it's uh 27 00:01:05,299 --> 00:01:12,320 unavoidable given the subject matter 28 00:01:09,360 --> 00:01:14,460 um so today we are going to talk about 29 00:01:12,320 --> 00:01:16,560 uh a few things we're going to talk 30 00:01:14,460 --> 00:01:19,200 about uh Wordle itself we're going to 31 00:01:16,560 --> 00:01:21,780 talk a bit about concurrency in Python 32 00:01:19,200 --> 00:01:23,580 and where things are at with that and 33 00:01:21,780 --> 00:01:27,600 also some things that are related to 34 00:01:23,580 --> 00:01:29,820 either Wordle and or concurrency 35 00:01:27,600 --> 00:01:31,619 um so I play wordal most days uh 36 00:01:29,820 --> 00:01:33,780 everyone else play Wordle 37 00:01:31,619 --> 00:01:34,979 wait who here is just here to watch me 38 00:01:33,780 --> 00:01:37,380 speak 39 00:01:34,979 --> 00:01:39,479 who's here for concurrency stuff 40 00:01:37,380 --> 00:01:41,159 okay right so all the people who are who 41 00:01:39,479 --> 00:01:43,439 are here for either of the two things in 42 00:01:41,159 --> 00:01:45,659 the middle will be slightly disappointed 43 00:01:43,439 --> 00:01:47,040 um so mediocre talk about Wordle a Medio 44 00:01:45,659 --> 00:01:48,540 could talk about concurrency hopefully 45 00:01:47,040 --> 00:01:50,939 two things together will be interesting 46 00:01:48,540 --> 00:01:53,759 I play wordal most days I play in hard 47 00:01:50,939 --> 00:01:55,860 mode I'm comfortably average at it 48 00:01:53,759 --> 00:01:58,140 um I usually take three or four guesses 49 00:01:55,860 --> 00:01:59,640 uh here's a picture from me playing on 50 00:01:58,140 --> 00:02:00,960 Wednesday where I managed to get it in 51 00:01:59,640 --> 00:02:03,420 two so I'm just making myself look 52 00:02:00,960 --> 00:02:06,360 better than I am my starting word these 53 00:02:03,420 --> 00:02:08,819 days is tears which I know for a fact is 54 00:02:06,360 --> 00:02:10,500 not a possible answer in Wordle as 55 00:02:08,819 --> 00:02:12,120 you'll see later it's what my solver 56 00:02:10,500 --> 00:02:14,760 thinks is the best possible starting 57 00:02:12,120 --> 00:02:16,379 word and who am I to argue with code 58 00:02:14,760 --> 00:02:21,000 that I've written 59 00:02:16,379 --> 00:02:22,440 uh my old starting word was irate uh if 60 00:02:21,000 --> 00:02:24,900 you play Wordle you'll know that that 61 00:02:22,440 --> 00:02:26,879 was an answer within the last month uh 62 00:02:24,900 --> 00:02:30,739 which is really disappointing because I 63 00:02:26,879 --> 00:02:30,739 started using the word Tears by then 64 00:02:31,440 --> 00:02:35,819 um anyway there's no actual spoilers in 65 00:02:34,260 --> 00:02:37,980 this talk I wrote most of the slides 66 00:02:35,819 --> 00:02:39,780 earlier this week I might have looked at 67 00:02:37,980 --> 00:02:41,340 wordlebot around then I wrote all the 68 00:02:39,780 --> 00:02:42,599 slides before I knew what today's word 69 00:02:41,340 --> 00:02:44,640 was and I've already forgotten what 70 00:02:42,599 --> 00:02:46,140 today's word was and also I think it's 71 00:02:44,640 --> 00:02:48,480 important to mention this talk probably 72 00:02:46,140 --> 00:02:52,140 won't change how you approach Wordle as 73 00:02:48,480 --> 00:02:54,060 a human being which I believe most of 74 00:02:52,140 --> 00:02:56,459 you are Beno 75 00:02:54,060 --> 00:02:58,560 um yeah exactly 76 00:02:56,459 --> 00:03:01,500 um I'd hate to spoil your enjoyment of a 77 00:02:58,560 --> 00:03:03,420 thing that's generally quite a pleasant 78 00:03:01,500 --> 00:03:04,080 thing that some of us 79 00:03:03,420 --> 00:03:06,420 um 80 00:03:04,080 --> 00:03:09,239 derive some level of enjoyment from 81 00:03:06,420 --> 00:03:12,060 so uh I don't think Wordle are solving 82 00:03:09,239 --> 00:03:13,560 world as a human uh resembles solving 83 00:03:12,060 --> 00:03:16,500 word or like a computer would because 84 00:03:13,560 --> 00:03:19,040 we're really not good as human beings at 85 00:03:16,500 --> 00:03:21,659 reasoning about a large amount of data 86 00:03:19,040 --> 00:03:24,120 in our heads and what do I mean by a 87 00:03:21,659 --> 00:03:26,819 large amount of data well according to 88 00:03:24,120 --> 00:03:30,120 the uh yet another word list word list 89 00:03:26,819 --> 00:03:32,480 that uh that a number of word games use 90 00:03:30,120 --> 00:03:35,640 there's 91 00:03:32,480 --> 00:03:36,659 12036 ish English language five letter 92 00:03:35,640 --> 00:03:38,940 words 93 00:03:36,659 --> 00:03:41,519 the solver that I use uses this word 94 00:03:38,940 --> 00:03:45,060 list and even if you filter out obvious 95 00:03:41,519 --> 00:03:47,220 plurals which uh Wordle itself does for 96 00:03:45,060 --> 00:03:48,180 its answer list there's still in excess 97 00:03:47,220 --> 00:03:50,879 of 98 00:03:48,180 --> 00:03:52,500 8 000-ish words it's really hard to keep 99 00:03:50,879 --> 00:03:54,840 that many words in your brain and reason 100 00:03:52,500 --> 00:03:56,879 about that sort of problem space now 101 00:03:54,840 --> 00:03:59,459 even after you make a good first guess 102 00:03:56,879 --> 00:04:00,900 which most people will have a good first 103 00:03:59,459 --> 00:04:04,260 guess there's there's normally somewhere 104 00:04:00,900 --> 00:04:05,760 between 60 and 500 Words left in the 105 00:04:04,260 --> 00:04:07,799 problem space to make your last five 106 00:04:05,760 --> 00:04:09,900 guesses with and 107 00:04:07,799 --> 00:04:12,540 even with that in mind it's really 108 00:04:09,900 --> 00:04:14,280 difficult to memorize which 60 to 500 109 00:04:12,540 --> 00:04:16,560 words are going to be left in in the 110 00:04:14,280 --> 00:04:18,239 list because every word will split that 111 00:04:16,560 --> 00:04:20,340 that set of English language words 112 00:04:18,239 --> 00:04:23,880 differently and so the way that most 113 00:04:20,340 --> 00:04:25,860 people go about solving Wordle is to uh 114 00:04:23,880 --> 00:04:27,900 basically just just do what everyone 115 00:04:25,860 --> 00:04:28,740 else does 116 00:04:27,900 --> 00:04:31,500 um 117 00:04:28,740 --> 00:04:34,320 and just to give you an idea of how well 118 00:04:31,500 --> 00:04:37,440 we can see how everyone else plays at 119 00:04:34,320 --> 00:04:39,720 Wordle uh the New York Times uh sometime 120 00:04:37,440 --> 00:04:41,340 after they bought out the the game they 121 00:04:39,720 --> 00:04:44,639 started collecting statistics because 122 00:04:41,340 --> 00:04:46,860 they're a tech company and they 123 00:04:44,639 --> 00:04:49,500 collected statistics and they made a 124 00:04:46,860 --> 00:04:52,500 site called wordlebot which is both a 125 00:04:49,500 --> 00:04:54,060 Wordle solver itself but also a site 126 00:04:52,500 --> 00:04:55,620 that will give you player statistics for 127 00:04:54,060 --> 00:04:57,060 playing Wordle and if you check in on 128 00:04:55,620 --> 00:04:59,880 wordlebot you get some interesting 129 00:04:57,060 --> 00:05:01,440 information particularly uh if you're an 130 00:04:59,880 --> 00:05:03,120 Australian person or somewhere on this 131 00:05:01,440 --> 00:05:05,820 side of the International Date Line you 132 00:05:03,120 --> 00:05:08,220 can join in on worldbot basically the 133 00:05:05,820 --> 00:05:09,840 moment people have started playing this 134 00:05:08,220 --> 00:05:12,660 is a screen grab from wordlebot on 135 00:05:09,840 --> 00:05:14,940 Wednesday morning uh here in Australia I 136 00:05:12,660 --> 00:05:17,460 took it at six a.m a dedication to 137 00:05:14,940 --> 00:05:20,100 Preparing slides and so really you've 138 00:05:17,460 --> 00:05:22,440 only got the early Rises and people from 139 00:05:20,100 --> 00:05:25,080 New Zealand here included in the stats 140 00:05:22,440 --> 00:05:27,360 and you can see that most people who 141 00:05:25,080 --> 00:05:28,880 play World earlier in that that 48 hour 142 00:05:27,360 --> 00:05:31,979 time window 143 00:05:28,880 --> 00:05:33,720 they they pick uh edu as their first 144 00:05:31,979 --> 00:05:35,699 word 145 00:05:33,720 --> 00:05:38,460 um why do people pick a year as their 146 00:05:35,699 --> 00:05:40,380 first word uh it's because it's got a 147 00:05:38,460 --> 00:05:41,940 lot of vowels in it and people think 148 00:05:40,380 --> 00:05:44,400 that figuring out which vowels will help 149 00:05:41,940 --> 00:05:46,320 them solve word or quickly and this is 150 00:05:44,400 --> 00:05:48,960 sort of a strategy that people latched 151 00:05:46,320 --> 00:05:51,060 on to very very early uh in the in the 152 00:05:48,960 --> 00:05:54,360 days of Wordle 153 00:05:51,060 --> 00:05:56,940 if you take a screen grab at 6am my time 154 00:05:54,360 --> 00:05:59,639 I live in California at the moment so I 155 00:05:56,940 --> 00:06:01,979 play wordal 17 hours later in California 156 00:05:59,639 --> 00:06:04,080 than I would in Australia and you can 157 00:06:01,979 --> 00:06:08,160 see that the most popular word is least 158 00:06:04,080 --> 00:06:08,880 a jerk is still up there it's number two 159 00:06:08,160 --> 00:06:10,320 um 160 00:06:08,880 --> 00:06:14,479 but what do you think has changed 161 00:06:10,320 --> 00:06:14,479 between uh between those 17 hours 162 00:06:14,520 --> 00:06:19,919 okay you've got everybody who subscribes 163 00:06:17,940 --> 00:06:22,800 to New York Times which nobody does in 164 00:06:19,919 --> 00:06:24,060 Australia uh who's looked at wordlebot 165 00:06:22,800 --> 00:06:25,500 and know that least is a better word 166 00:06:24,060 --> 00:06:26,880 than endure because the New York Times 167 00:06:25,500 --> 00:06:28,740 says so and they use it as their 168 00:06:26,880 --> 00:06:30,419 starting word New York Times actually no 169 00:06:28,740 --> 00:06:31,800 longer says that they say slate is the 170 00:06:30,419 --> 00:06:33,419 best starting word and that's now number 171 00:06:31,800 --> 00:06:34,440 three 172 00:06:33,419 --> 00:06:35,940 um 173 00:06:34,440 --> 00:06:37,740 and so once you make your first guess 174 00:06:35,940 --> 00:06:39,479 generally it's really just down to 175 00:06:37,740 --> 00:06:41,340 remembering a few good second guesses 176 00:06:39,479 --> 00:06:42,600 remembering some patterns and then the 177 00:06:41,340 --> 00:06:44,699 further you get into the game it's 178 00:06:42,600 --> 00:06:47,220 really just down to how much you can 179 00:06:44,699 --> 00:06:48,360 make educated guesses about 180 00:06:47,220 --> 00:06:51,180 um 181 00:06:48,360 --> 00:06:53,039 about what the answer is so yeah we we 182 00:06:51,180 --> 00:06:55,080 really don't have the mental capacity to 183 00:06:53,039 --> 00:06:57,060 play word or like a computer at all uh 184 00:06:55,080 --> 00:06:58,740 Wordle can play a lot closer to 185 00:06:57,060 --> 00:07:00,600 optimally 186 00:06:58,740 --> 00:07:03,240 um Wordle is a guessing game and and the 187 00:07:00,600 --> 00:07:05,460 way to play a guessing game is to make a 188 00:07:03,240 --> 00:07:07,979 guess of uh I guess that we think will 189 00:07:05,460 --> 00:07:09,419 reveal the most information about a 190 00:07:07,979 --> 00:07:12,539 solution space 191 00:07:09,419 --> 00:07:16,199 to a problem and thankfully information 192 00:07:12,539 --> 00:07:18,000 is a Lo uh is a formal term and we can 193 00:07:16,199 --> 00:07:21,120 use that formal term to figure out how 194 00:07:18,000 --> 00:07:22,440 to build a solver for for Wordle but I'm 195 00:07:21,120 --> 00:07:24,300 not going to build a solver for word or 196 00:07:22,440 --> 00:07:26,400 firstly I'm going to discuss a simpler 197 00:07:24,300 --> 00:07:27,780 game to play which is the guessing game 198 00:07:26,400 --> 00:07:30,360 where you have to guess a number between 199 00:07:27,780 --> 00:07:31,919 one and a thousand and the game will 200 00:07:30,360 --> 00:07:35,099 tell you if the answer is higher or 201 00:07:31,919 --> 00:07:37,440 lower so what's our first guess 202 00:07:35,099 --> 00:07:39,900 right you guess the number in the middle 203 00:07:37,440 --> 00:07:42,599 and then immediately the solution space 204 00:07:39,900 --> 00:07:43,979 gets halved and then you can guess the 205 00:07:42,599 --> 00:07:46,220 middle of that space and you'll have the 206 00:07:43,979 --> 00:07:48,900 solution every single time 207 00:07:46,220 --> 00:07:51,300 and with this game you can play 208 00:07:48,900 --> 00:07:53,160 optimally and you know like unless you 209 00:07:51,300 --> 00:07:55,139 accidentally happen on one of those 210 00:07:53,160 --> 00:07:56,699 answers you will know exactly how many 211 00:07:55,139 --> 00:07:59,240 guesses it will take you to get to the 212 00:07:56,699 --> 00:07:59,240 correct answer 213 00:08:00,000 --> 00:08:04,560 so so back to this idea of information 214 00:08:02,340 --> 00:08:07,440 every time you halve the solution space 215 00:08:04,560 --> 00:08:10,620 the the base two log of the size of the 216 00:08:07,440 --> 00:08:12,960 solution space reduces by about one 217 00:08:10,620 --> 00:08:16,080 um if there were 1024 spaces it would 218 00:08:12,960 --> 00:08:17,580 Reduce by one uh every single time so we 219 00:08:16,080 --> 00:08:20,879 described this halving of the solution 220 00:08:17,580 --> 00:08:23,819 space as gaining one bit of information 221 00:08:20,879 --> 00:08:25,500 so the idea of expected Information Gain 222 00:08:23,819 --> 00:08:29,039 Is that the base two log of the solution 223 00:08:25,500 --> 00:08:30,840 space less the expected base two log of 224 00:08:29,039 --> 00:08:33,479 the solution space after guess is your 225 00:08:30,840 --> 00:08:35,940 expected Information Gain so for our 226 00:08:33,479 --> 00:08:39,240 guessing game that expected Information 227 00:08:35,940 --> 00:08:40,560 Gain is always going to be basically one 228 00:08:39,240 --> 00:08:42,959 bit 229 00:08:40,560 --> 00:08:45,060 so what about Wordle 230 00:08:42,959 --> 00:08:46,560 we can we can sort of apply these 231 00:08:45,060 --> 00:08:48,360 theories to Wordle but the difference is 232 00:08:46,560 --> 00:08:50,399 with Wordle you can't actually play 233 00:08:48,360 --> 00:08:52,920 optimal you can't be guaranteed to play 234 00:08:50,399 --> 00:08:54,740 optimally uh the same guess is going to 235 00:08:52,920 --> 00:08:57,300 reveal different amounts of information 236 00:08:54,740 --> 00:08:58,740 depending on what the actual answer is 237 00:08:57,300 --> 00:09:01,440 so the best thing that you can do is 238 00:08:58,740 --> 00:09:03,120 make an estimate and so we can also 239 00:09:01,440 --> 00:09:06,360 figure out how good our estimate needs 240 00:09:03,120 --> 00:09:07,740 to be we can see that the solution space 241 00:09:06,360 --> 00:09:09,540 for 242 00:09:07,740 --> 00:09:12,120 um for the set of five letter words in 243 00:09:09,540 --> 00:09:14,580 English language is about 14 bits and 244 00:09:12,120 --> 00:09:17,399 that means that we need to reveal about 245 00:09:14,580 --> 00:09:18,600 2.33 bits of information per guess which 246 00:09:17,399 --> 00:09:21,240 means 247 00:09:18,600 --> 00:09:23,580 um somewhere between splitting the 248 00:09:21,240 --> 00:09:24,720 solution space into a quarter to an 249 00:09:23,580 --> 00:09:26,760 eighth somewhere in that sort of space 250 00:09:24,720 --> 00:09:29,700 you need to do each guess in order to 251 00:09:26,760 --> 00:09:32,519 get in guess the solution in six guesses 252 00:09:29,700 --> 00:09:34,440 or less so back to my starting starting 253 00:09:32,519 --> 00:09:38,399 word here is a worked example from a few 254 00:09:34,440 --> 00:09:42,000 weeks ago uh I took my my solving codes 255 00:09:38,399 --> 00:09:44,640 uh preferred first word and I got a 256 00:09:42,000 --> 00:09:48,720 green tea and a yellow a 257 00:09:44,640 --> 00:09:50,519 so if I guess the word today depending 258 00:09:48,720 --> 00:09:52,260 on the information revealed to me I 259 00:09:50,519 --> 00:09:54,600 might end up with three potential 260 00:09:52,260 --> 00:09:56,760 answers or I might end up with only one 261 00:09:54,600 --> 00:09:59,339 potential solution remaining so that's 262 00:09:56,760 --> 00:10:02,160 13 potential answers in that solution 263 00:09:59,339 --> 00:10:04,500 space it gets split up into seven groups 264 00:10:02,160 --> 00:10:06,060 and so the expected number of solutions 265 00:10:04,500 --> 00:10:09,420 I have after the guess is going to be 266 00:10:06,060 --> 00:10:10,860 1.86 words and that's a gain of 2.81 267 00:10:09,420 --> 00:10:13,019 bits of information which is better than 268 00:10:10,860 --> 00:10:15,180 the 2.33 we need 269 00:10:13,019 --> 00:10:17,700 on the other hand if I had guessed the 270 00:10:15,180 --> 00:10:19,740 word Titan I'll still end up with either 271 00:10:17,700 --> 00:10:21,600 three words or one word remaining but 272 00:10:19,740 --> 00:10:24,480 there's far more ways for me to end up 273 00:10:21,600 --> 00:10:26,279 with just one word uh than three and so 274 00:10:24,480 --> 00:10:28,380 that's 13 words split up into nine 275 00:10:26,279 --> 00:10:31,080 groups which means I have an expected 276 00:10:28,380 --> 00:10:34,440 number of solutions of 1.44 which is a 277 00:10:31,080 --> 00:10:36,540 gain of 3.17 bits of information 278 00:10:34,440 --> 00:10:39,540 so that gives us a strategy for playing 279 00:10:36,540 --> 00:10:41,459 Wordle the idea is to pick the word with 280 00:10:39,540 --> 00:10:43,860 the smallest expected solution space 281 00:10:41,459 --> 00:10:45,420 size uh make a guess with that word and 282 00:10:43,860 --> 00:10:47,100 then eliminate all those words from a 283 00:10:45,420 --> 00:10:48,600 set of answers and repeat that and 284 00:10:47,100 --> 00:10:50,700 repeat that and repeat that until only 285 00:10:48,600 --> 00:10:53,160 one word remains 286 00:10:50,700 --> 00:10:55,380 so let's look at some python code this 287 00:10:53,160 --> 00:10:57,300 is a python conference after all here's 288 00:10:55,380 --> 00:11:00,660 what the main Loop of my Wordle solver 289 00:10:57,300 --> 00:11:01,920 looks like we make a guess and then we 290 00:11:00,660 --> 00:11:03,899 classify the guess that we've made 291 00:11:01,920 --> 00:11:05,700 against the actual Target word and then 292 00:11:03,899 --> 00:11:08,399 we filter the solution space against the 293 00:11:05,700 --> 00:11:10,560 classification that we get just as an 294 00:11:08,399 --> 00:11:13,320 aside I structure a lot of my code like 295 00:11:10,560 --> 00:11:16,260 this with a high level with a high level 296 00:11:13,320 --> 00:11:18,839 top level function that can be split out 297 00:11:16,260 --> 00:11:21,420 into easily testable functions only one 298 00:11:18,839 --> 00:11:23,220 of these things is going to be subjected 299 00:11:21,420 --> 00:11:26,040 to concurrency later on which is uh 300 00:11:23,220 --> 00:11:28,140 which is Handy so let's take a look at 301 00:11:26,040 --> 00:11:30,060 the second of those two steps uh this is 302 00:11:28,140 --> 00:11:32,640 a classification routine I'm using in a 303 00:11:30,060 --> 00:11:34,140 num to describe whether the letter is in 304 00:11:32,640 --> 00:11:35,940 the solution or not and numbers are 305 00:11:34,140 --> 00:11:37,920 great you should use them 306 00:11:35,940 --> 00:11:40,200 um it says whether the letter is yellow 307 00:11:37,920 --> 00:11:42,120 or green and then it just returns a five 308 00:11:40,200 --> 00:11:44,339 Tuple of these classification objects 309 00:11:42,120 --> 00:11:46,320 which can then be used as keys in a 310 00:11:44,339 --> 00:11:49,440 dictionary you'll see why being used 311 00:11:46,320 --> 00:11:51,420 these used whether why these should be 312 00:11:49,440 --> 00:11:54,120 used as keys in a dictionary uh that's 313 00:11:51,420 --> 00:11:55,620 important kind of later on which is is 314 00:11:54,120 --> 00:11:57,060 it here no it's not uh here's the 315 00:11:55,620 --> 00:11:59,820 implementation of the filtering function 316 00:11:57,060 --> 00:12:01,920 it takes those classification uh five 317 00:11:59,820 --> 00:12:03,480 tubules and it runs them against every 318 00:12:01,920 --> 00:12:05,760 word in the solution space and it 319 00:12:03,480 --> 00:12:08,880 returns only the words in the solution 320 00:12:05,760 --> 00:12:11,940 space that match the classification 321 00:12:08,880 --> 00:12:14,700 I've written this solver three times and 322 00:12:11,940 --> 00:12:16,860 and every single time I've written a a 323 00:12:14,700 --> 00:12:18,240 four else block here 324 00:12:16,860 --> 00:12:20,459 um 325 00:12:18,240 --> 00:12:22,079 with like I've had the opportunity to 326 00:12:20,459 --> 00:12:23,880 decide not to do that and it's always 327 00:12:22,079 --> 00:12:25,019 been the right idea as far as the code 328 00:12:23,880 --> 00:12:29,240 I've written 329 00:12:25,019 --> 00:12:29,240 um sometimes it's justifiable 330 00:12:31,320 --> 00:12:34,680 so here's the point where we actually 331 00:12:32,940 --> 00:12:36,480 make a guess 332 00:12:34,680 --> 00:12:38,760 so the first function that we're going 333 00:12:36,480 --> 00:12:40,440 to try to do to make guesses is just to 334 00:12:38,760 --> 00:12:43,680 Loop through the space of possible 335 00:12:40,440 --> 00:12:45,839 guesses find the potential gas with the 336 00:12:43,680 --> 00:12:46,920 lowest potential score which is the the 337 00:12:45,839 --> 00:12:49,139 number of 338 00:12:46,920 --> 00:12:50,820 um the number of groups of words also 339 00:12:49,139 --> 00:12:53,700 the average number of answers in each 340 00:12:50,820 --> 00:12:55,380 group there's no tie break facility here 341 00:12:53,700 --> 00:12:57,120 which means it might not always make an 342 00:12:55,380 --> 00:12:59,160 ideal guess you'll you'll see the effect 343 00:12:57,120 --> 00:13:00,779 of that later on 344 00:12:59,160 --> 00:13:02,339 and then the scoring function there's 345 00:13:00,779 --> 00:13:04,560 there's another for Loop in that we go 346 00:13:02,339 --> 00:13:06,779 through every potential answer classify 347 00:13:04,560 --> 00:13:09,000 our guess as if the potential answer is 348 00:13:06,779 --> 00:13:11,459 the actual answer and then see how that 349 00:13:09,000 --> 00:13:13,380 guess would split the solution space so 350 00:13:11,459 --> 00:13:15,180 the more groups the smaller the solution 351 00:13:13,380 --> 00:13:16,860 space is likely to be after the guess 352 00:13:15,180 --> 00:13:18,660 and we just average that for every 353 00:13:16,860 --> 00:13:21,240 potential answer 354 00:13:18,660 --> 00:13:22,860 so uh I guess the first question is does 355 00:13:21,240 --> 00:13:25,019 this approach actually work well does 356 00:13:22,860 --> 00:13:28,079 this solve the problem that we have so 357 00:13:25,019 --> 00:13:30,300 I'm using the target word snake and you 358 00:13:28,079 --> 00:13:34,079 can see that it solves the word or in 359 00:13:30,300 --> 00:13:35,880 Easy Mode in five guesses a lot of these 360 00:13:34,079 --> 00:13:37,019 words are really really obscure and 361 00:13:35,880 --> 00:13:40,260 probably not ones that I would guess 362 00:13:37,019 --> 00:13:42,480 personally uh spelled means to Splinter 363 00:13:40,260 --> 00:13:44,700 or chip 364 00:13:42,480 --> 00:13:46,560 uh before I move on there's one code 365 00:13:44,700 --> 00:13:48,899 simplification that I suggest using this 366 00:13:46,560 --> 00:13:50,579 is what my actual code does uh here's 367 00:13:48,899 --> 00:13:52,860 our make guess function it's a lot of 368 00:13:50,579 --> 00:13:54,839 python code it can be Rewritten like 369 00:13:52,860 --> 00:13:57,300 this which has the nice effect of 370 00:13:54,839 --> 00:13:58,980 running the outer loop in C code it 371 00:13:57,300 --> 00:14:01,620 makes things somewhat but not 372 00:13:58,980 --> 00:14:03,779 importantly faster so there we go we can 373 00:14:01,620 --> 00:14:06,660 solve Wordle in about three minutes on 374 00:14:03,779 --> 00:14:08,639 my M1 MacBook here so can we do better 375 00:14:06,660 --> 00:14:10,680 in Python 376 00:14:08,639 --> 00:14:12,779 so the first place you might start is 377 00:14:10,680 --> 00:14:14,399 looking at thread pools threads are 378 00:14:12,779 --> 00:14:17,459 chains of execution that exist within 379 00:14:14,399 --> 00:14:19,560 the same process segment on your system 380 00:14:17,459 --> 00:14:21,779 here is our make guess function and 381 00:14:19,560 --> 00:14:23,820 again we have this Loop and we do 382 00:14:21,779 --> 00:14:25,740 exactly the same thing every single time 383 00:14:23,820 --> 00:14:27,959 without modifying any data structures 384 00:14:25,740 --> 00:14:30,060 and then the inside of that Loop is also 385 00:14:27,959 --> 00:14:32,519 quite resource intensive you there's 386 00:14:30,060 --> 00:14:33,600 there's two nested for Loops 387 00:14:32,519 --> 00:14:35,339 um 388 00:14:33,600 --> 00:14:37,320 so there's that and so we can we can 389 00:14:35,339 --> 00:14:38,940 pull this out and this is where the 390 00:14:37,320 --> 00:14:41,579 concurrent Futures Library comes in in 391 00:14:38,940 --> 00:14:43,440 Python it is often my first Port of Call 392 00:14:41,579 --> 00:14:46,440 for any sort of asynchronous programming 393 00:14:43,440 --> 00:14:48,000 even before using async await 394 00:14:46,440 --> 00:14:49,440 um it's I find it somewhat easier to 395 00:14:48,000 --> 00:14:52,019 conceptually put things together that 396 00:14:49,440 --> 00:14:53,820 way your mileage may vary uh it's 397 00:14:52,019 --> 00:14:55,260 definitely much easier than writing raw 398 00:14:53,820 --> 00:14:57,779 threads in Python if you have a problem 399 00:14:55,260 --> 00:14:59,579 that's amenable to threading so you can 400 00:14:57,779 --> 00:15:01,500 think in terms of of calling functions 401 00:14:59,579 --> 00:15:03,420 and waiting for a result rather than 402 00:15:01,500 --> 00:15:05,579 working with things like locks which I 403 00:15:03,420 --> 00:15:07,740 think are a bit tedious and and prone to 404 00:15:05,579 --> 00:15:09,480 getting those things wrong uh so here's 405 00:15:07,740 --> 00:15:11,160 what our make guess function looks like 406 00:15:09,480 --> 00:15:14,160 with a thread pool 407 00:15:11,160 --> 00:15:16,320 we submit each potential guess to the 408 00:15:14,160 --> 00:15:18,899 thread pool which returns a future which 409 00:15:16,320 --> 00:15:20,459 is an object that will eventually hold 410 00:15:18,899 --> 00:15:22,440 the result of the guests that we made 411 00:15:20,459 --> 00:15:23,820 and then we're going to associate that 412 00:15:22,440 --> 00:15:25,260 future with the word that we use to 413 00:15:23,820 --> 00:15:27,120 submit it so we can actually get a score 414 00:15:25,260 --> 00:15:29,699 back and know which word it was that 415 00:15:27,120 --> 00:15:31,440 generated the best result we're still 416 00:15:29,699 --> 00:15:34,500 using that Min built in that I used in 417 00:15:31,440 --> 00:15:36,420 that that code Improvement we grab each 418 00:15:34,500 --> 00:15:38,880 result as it comes out of the thread 419 00:15:36,420 --> 00:15:40,800 pool complete and by you we do that by 420 00:15:38,880 --> 00:15:42,300 using the the as completed function 421 00:15:40,800 --> 00:15:43,579 which is in the concurrent Futures 422 00:15:42,300 --> 00:15:45,899 Library 423 00:15:43,579 --> 00:15:48,120 so we can set up a thread pool with 424 00:15:45,899 --> 00:15:49,740 eight workers I have only eight cores in 425 00:15:48,120 --> 00:15:51,260 my machine so we won't get more than an 426 00:15:49,740 --> 00:15:53,519 eight-time speed up 427 00:15:51,260 --> 00:15:55,800 and we can go from our looping code 428 00:15:53,519 --> 00:15:59,279 which takes 185 seconds to make its 429 00:15:55,800 --> 00:16:03,139 first guess oh uh Vemma by the way a 430 00:15:59,279 --> 00:16:03,139 westphalian vigilante Society 431 00:16:03,860 --> 00:16:09,199 and here's our threaded code which takes 432 00:16:06,240 --> 00:16:12,120 181 seconds to make a guess 433 00:16:09,199 --> 00:16:13,980 uh why 434 00:16:12,120 --> 00:16:15,180 the Gill yeah 435 00:16:13,980 --> 00:16:17,760 um so this is where I point out that 436 00:16:15,180 --> 00:16:20,100 python has a global interpreter lock uh 437 00:16:17,760 --> 00:16:22,680 the global interpreter lock is a it's a 438 00:16:20,100 --> 00:16:24,660 it's a lock it prevents multiple threads 439 00:16:22,680 --> 00:16:27,420 from having access to any piece of state 440 00:16:24,660 --> 00:16:30,360 that is held by the python interpreter 441 00:16:27,420 --> 00:16:33,959 um in practice this means that only one 442 00:16:30,360 --> 00:16:35,699 python thread can execute it once 443 00:16:33,959 --> 00:16:37,380 I think it's actually quite interesting 444 00:16:35,699 --> 00:16:40,019 to note here that the guild basically 445 00:16:37,380 --> 00:16:43,639 prevents concurrency but it's very very 446 00:16:40,019 --> 00:16:46,860 very efficient at preventing concurrency 447 00:16:43,639 --> 00:16:48,420 we don't actually get any slowdown from 448 00:16:46,860 --> 00:16:50,459 various threads having to acquire and 449 00:16:48,420 --> 00:16:51,959 release the guild here we it runs in 450 00:16:50,459 --> 00:16:54,120 basically exactly the same amount of 451 00:16:51,959 --> 00:16:55,620 time it's like five seconds difference 452 00:16:54,120 --> 00:16:58,100 that difference is down to me running 453 00:16:55,620 --> 00:17:00,180 Chrome on my computer at the same time 454 00:16:58,100 --> 00:17:02,040 don't do that if you're trying to do 455 00:17:00,180 --> 00:17:04,199 scientific analysis of your your speed 456 00:17:02,040 --> 00:17:05,220 up that's a really bad idea 457 00:17:04,199 --> 00:17:07,860 um 458 00:17:05,220 --> 00:17:10,020 so are our threads useful in Python with 459 00:17:07,860 --> 00:17:11,579 with the girl uh yes if you have 460 00:17:10,020 --> 00:17:13,140 parallel code that's not written in 461 00:17:11,579 --> 00:17:16,140 Python and you can release the Gill on 462 00:17:13,140 --> 00:17:17,699 each thread if your parallel code is IO 463 00:17:16,140 --> 00:17:20,220 bound but only up to a certain amount 464 00:17:17,699 --> 00:17:22,260 only to a certain extent async is much 465 00:17:20,220 --> 00:17:24,839 better for that if you can run your code 466 00:17:22,260 --> 00:17:26,459 on Pi Pi and things will be better it's 467 00:17:24,839 --> 00:17:29,040 really not good for writing a wordal 468 00:17:26,459 --> 00:17:31,679 solver uh so the next thing we can try 469 00:17:29,040 --> 00:17:33,660 is a thing called process pools so 470 00:17:31,679 --> 00:17:35,820 processors are spaces of execution that 471 00:17:33,660 --> 00:17:37,140 are managed by your operating system and 472 00:17:35,820 --> 00:17:39,480 they have their own memory they don't 473 00:17:37,140 --> 00:17:41,580 share memory between uh between multiple 474 00:17:39,480 --> 00:17:42,960 processors uh in practice it's really 475 00:17:41,580 --> 00:17:44,940 only possible to communicate between 476 00:17:42,960 --> 00:17:47,400 processes over things like sockets or 477 00:17:44,940 --> 00:17:48,419 files or specially declared shared 478 00:17:47,400 --> 00:17:51,059 memory that your operating system 479 00:17:48,419 --> 00:17:53,940 manages for you the good news about 480 00:17:51,059 --> 00:17:56,100 processes is that there's one Gill per 481 00:17:53,940 --> 00:17:59,280 python process so if you have multiple 482 00:17:56,100 --> 00:18:00,840 processes you only uh have you have one 483 00:17:59,280 --> 00:18:03,000 deal per process and you should actually 484 00:18:00,840 --> 00:18:05,820 see some speed up and if you're using 485 00:18:03,000 --> 00:18:07,620 the concurrent Futures Library 486 00:18:05,820 --> 00:18:10,919 the only real difference between using 487 00:18:07,620 --> 00:18:13,320 threads and processors is defining what 488 00:18:10,919 --> 00:18:14,940 sort of pool you use so I'm using a 489 00:18:13,320 --> 00:18:16,559 process pool executor instead of a 490 00:18:14,940 --> 00:18:18,480 thread pool executor 491 00:18:16,559 --> 00:18:23,460 and to remind you our single threaded 492 00:18:18,480 --> 00:18:26,940 code talk 185 seconds to make a guess 493 00:18:23,460 --> 00:18:29,460 with processpool executor it it took 38 494 00:18:26,940 --> 00:18:32,700 seconds which is actually a speed up 495 00:18:29,460 --> 00:18:34,620 which is cool it's about 4.8 times 496 00:18:32,700 --> 00:18:36,000 so what if we wanted to see if we can 497 00:18:34,620 --> 00:18:38,880 get more speed up well we can change 498 00:18:36,000 --> 00:18:41,940 this Max worker's parameter to eight uh 499 00:18:38,880 --> 00:18:45,539 from 8 to 16 and it goes from 38 seconds 500 00:18:41,940 --> 00:18:50,160 under eight workers to more than 38 501 00:18:45,539 --> 00:18:53,039 seconds this again is because I have 502 00:18:50,160 --> 00:18:55,080 I have only eight cores on my laptop so 503 00:18:53,039 --> 00:18:56,760 my laptop only has eight cores which is 504 00:18:55,080 --> 00:18:59,160 obviously the maximum speed up I can get 505 00:18:56,760 --> 00:19:01,320 16 processors can't run on eight cores 506 00:18:59,160 --> 00:19:03,240 at once but I only got 4.8 times speed 507 00:19:01,320 --> 00:19:04,980 up uh with uh with switching to a 508 00:19:03,240 --> 00:19:08,100 process pool 509 00:19:04,980 --> 00:19:09,419 um this is where I go into our uh into 510 00:19:08,100 --> 00:19:11,400 our undergraduate computer science 511 00:19:09,419 --> 00:19:13,260 curriculum and talk about amdel's law if 512 00:19:11,400 --> 00:19:14,820 you know about that you can you can 513 00:19:13,260 --> 00:19:16,440 check it off now but for everyone else 514 00:19:14,820 --> 00:19:18,059 the quick explanation is that a 515 00:19:16,440 --> 00:19:20,400 programming task can be split into Parts 516 00:19:18,059 --> 00:19:22,020 the Wordle solver has three you can 517 00:19:20,400 --> 00:19:23,340 score every word you need to do that you 518 00:19:22,020 --> 00:19:24,900 need to find the minimum by looking at 519 00:19:23,340 --> 00:19:27,600 every single word and then you need to 520 00:19:24,900 --> 00:19:29,280 filter the list of solutions the scoring 521 00:19:27,600 --> 00:19:31,559 task can be split up into chunks and you 522 00:19:29,280 --> 00:19:33,660 can run all those bits in parallel 523 00:19:31,559 --> 00:19:35,160 the bits that run in sequence cannot be 524 00:19:33,660 --> 00:19:36,960 run in parallel because they run in 525 00:19:35,160 --> 00:19:38,580 sequence and that establishes a limit on 526 00:19:36,960 --> 00:19:41,640 the amount our program can be sped up 527 00:19:38,580 --> 00:19:43,440 but also in reality there's a bunch of 528 00:19:41,640 --> 00:19:45,480 work the operating system needs to do in 529 00:19:43,440 --> 00:19:47,100 order to coordinate all these processes 530 00:19:45,480 --> 00:19:49,140 to deal with shared memory those sorts 531 00:19:47,100 --> 00:19:50,880 of things that gets added into our 532 00:19:49,140 --> 00:19:53,640 execution time and that coordination 533 00:19:50,880 --> 00:19:55,080 actually increases as we start to add 534 00:19:53,640 --> 00:19:57,120 more processes beyond the number of 535 00:19:55,080 --> 00:19:59,940 cores that we have on our system and 536 00:19:57,120 --> 00:20:01,980 that's where that extra slowdown came on 537 00:19:59,940 --> 00:20:03,660 so maybe there are other bits that we 538 00:20:01,980 --> 00:20:05,760 can run in parallel maybe we can run the 539 00:20:03,660 --> 00:20:07,740 filtering operation 540 00:20:05,760 --> 00:20:09,539 um it turns out that really just doesn't 541 00:20:07,740 --> 00:20:12,960 do much it actually in fact slightly 542 00:20:09,539 --> 00:20:14,880 slows down things because there's not a 543 00:20:12,960 --> 00:20:16,620 whole lot of well there's actually too 544 00:20:14,880 --> 00:20:18,960 much inter-process communication going 545 00:20:16,620 --> 00:20:20,940 on in that filter operation 546 00:20:18,960 --> 00:20:22,559 so to get a task from one process to 547 00:20:20,940 --> 00:20:25,440 another it actually has to be explicitly 548 00:20:22,559 --> 00:20:27,179 communicated and that takes time that's 549 00:20:25,440 --> 00:20:29,100 this sort of os coordination thing I 550 00:20:27,179 --> 00:20:31,440 showed in that diagram earlier uh 551 00:20:29,100 --> 00:20:33,299 processes they work best process pools 552 00:20:31,440 --> 00:20:35,280 work best if you can have longer running 553 00:20:33,299 --> 00:20:37,320 tasks that don't need to communicate 554 00:20:35,280 --> 00:20:39,480 very often and that gives us another 555 00:20:37,320 --> 00:20:40,559 insight into how to make things a bit 556 00:20:39,480 --> 00:20:42,780 faster 557 00:20:40,559 --> 00:20:44,880 so instead of submitting thousands of 558 00:20:42,780 --> 00:20:47,179 relatively small tasks into the process 559 00:20:44,880 --> 00:20:49,559 pool if we spend some time actually 560 00:20:47,179 --> 00:20:51,179 breaking up our problem space into as 561 00:20:49,559 --> 00:20:53,460 many cores that we have and running 562 00:20:51,179 --> 00:20:55,620 those sequentially we can solve the 563 00:20:53,460 --> 00:20:57,539 problem locally within each of the each 564 00:20:55,620 --> 00:21:00,080 chunk of the problem space and then find 565 00:20:57,539 --> 00:21:02,520 the global solution afterwards 566 00:21:00,080 --> 00:21:04,200 so we're actually just making use of the 567 00:21:02,520 --> 00:21:06,120 the make guess with Loop function that 568 00:21:04,200 --> 00:21:08,160 we wrote earlier and we're only doing 16 569 00:21:06,120 --> 00:21:10,440 pieces of inter-process communication 570 00:21:08,160 --> 00:21:12,480 instead of the 24 000 pieces of 571 00:21:10,440 --> 00:21:14,580 inter-process communication that we were 572 00:21:12,480 --> 00:21:17,100 doing with the obvious way of chunking 573 00:21:14,580 --> 00:21:19,380 things up and so here's our version 574 00:21:17,100 --> 00:21:20,760 without chunking up the inputs this is 575 00:21:19,380 --> 00:21:22,320 the one with lots of inter-process 576 00:21:20,760 --> 00:21:25,440 communication because we're submitting 577 00:21:22,320 --> 00:21:28,020 small tasks uh 24 000 small tasks into 578 00:21:25,440 --> 00:21:29,520 16 no 12 000 small tasks into the 579 00:21:28,020 --> 00:21:32,280 process pool 580 00:21:29,520 --> 00:21:34,320 um it takes that long uh here's the 581 00:21:32,280 --> 00:21:37,260 version where we're only doing eight 582 00:21:34,320 --> 00:21:38,940 submissions into the process pool you'll 583 00:21:37,260 --> 00:21:40,559 also notice that the opening word is 584 00:21:38,940 --> 00:21:43,020 different this is because our 585 00:21:40,559 --> 00:21:44,820 tie-breaking behavior is not really 586 00:21:43,020 --> 00:21:46,980 deterministic it really depends on what 587 00:21:44,820 --> 00:21:51,179 thing comes first out of the process 588 00:21:46,980 --> 00:21:53,820 pool so instead of Tears we have hairs 589 00:21:51,179 --> 00:21:59,120 um it is faster by a noticeable margin 590 00:21:53,820 --> 00:21:59,120 uh Sports by the way it means brittle 591 00:21:59,340 --> 00:22:05,640 so uh process pools they are good if you 592 00:22:02,520 --> 00:22:08,580 have a small number of large but CPU 593 00:22:05,640 --> 00:22:10,200 bounded tasks it takes a lot more work 594 00:22:08,580 --> 00:22:11,700 to set these up efficiently you need to 595 00:22:10,200 --> 00:22:13,980 think about how you split your problem 596 00:22:11,700 --> 00:22:15,720 space up such that you reduce the amount 597 00:22:13,980 --> 00:22:17,580 of inter-process communication you have 598 00:22:15,720 --> 00:22:19,140 this is different to how you would deal 599 00:22:17,580 --> 00:22:21,419 with threads in a language like C or 600 00:22:19,140 --> 00:22:24,600 Java and it's reasonably good for 601 00:22:21,419 --> 00:22:27,059 writing a word or solver I included the 602 00:22:24,600 --> 00:22:28,320 word async in the title of the talk 603 00:22:27,059 --> 00:22:30,120 um 604 00:22:28,320 --> 00:22:31,620 that's only because I need the third 605 00:22:30,120 --> 00:22:33,360 five letter word that was relevant to 606 00:22:31,620 --> 00:22:35,360 concurrency 607 00:22:33,360 --> 00:22:35,360 um 608 00:22:35,880 --> 00:22:39,419 it has it has the it has the same 609 00:22:37,860 --> 00:22:42,179 problem as thread pools in that 610 00:22:39,419 --> 00:22:43,980 everything runs within the same um uh 611 00:22:42,179 --> 00:22:46,260 within the same process space as python 612 00:22:43,980 --> 00:22:47,820 so you'd always end up with uh you'd 613 00:22:46,260 --> 00:22:48,960 always end up with something related to 614 00:22:47,820 --> 00:22:50,640 the Gill if you had a different event 615 00:22:48,960 --> 00:22:52,260 Loop that did allow for thread based 616 00:22:50,640 --> 00:22:54,059 concurrency if you dealt with process 617 00:22:52,260 --> 00:22:55,620 based concurrency well you're dealing 618 00:22:54,059 --> 00:22:57,120 with a whole lot of language level 619 00:22:55,620 --> 00:22:58,559 complication that would make things 620 00:22:57,120 --> 00:23:01,500 slower 621 00:22:58,559 --> 00:23:04,679 finally let's talk about no Gill because 622 00:23:01,500 --> 00:23:06,299 as I mentioned python has a gill it's 623 00:23:04,679 --> 00:23:07,919 always had a girl and people have always 624 00:23:06,299 --> 00:23:09,419 wanted the guild to go away because it 625 00:23:07,919 --> 00:23:12,179 gets in the way of using threads 626 00:23:09,419 --> 00:23:15,120 efficiently there is a new effort called 627 00:23:12,179 --> 00:23:17,640 nogill which is about the fifth effort 628 00:23:15,120 --> 00:23:19,559 that I've seen in the last 10 years and 629 00:23:17,640 --> 00:23:21,179 it seems to be making some level of 630 00:23:19,559 --> 00:23:21,960 progress 631 00:23:21,179 --> 00:23:23,880 um 632 00:23:21,960 --> 00:23:25,500 in terms of making like using 633 00:23:23,880 --> 00:23:27,600 concurrency in Python without the guild 634 00:23:25,500 --> 00:23:29,460 actually usable you can install no Gill 635 00:23:27,600 --> 00:23:32,520 very easily if you have pione on your 636 00:23:29,460 --> 00:23:34,460 machine just go power and install nogill 637 00:23:32,520 --> 00:23:37,320 3 9 10-1 638 00:23:34,460 --> 00:23:39,000 it is only supported in Python three 639 00:23:37,320 --> 00:23:39,840 nine 640 00:23:39,000 --> 00:23:42,860 um 641 00:23:39,840 --> 00:23:45,780 this is important because in Python 311 642 00:23:42,860 --> 00:23:48,840 uh the there's a team at Microsoft 643 00:23:45,780 --> 00:23:51,120 running the faster C python project and 644 00:23:48,840 --> 00:23:53,520 the faster C python project did a lot of 645 00:23:51,120 --> 00:23:55,140 work to make C python faster and they 646 00:23:53,520 --> 00:23:58,440 actually succeeded and all their work 647 00:23:55,140 --> 00:24:01,620 landed in Python 311. so our first guess 648 00:23:58,440 --> 00:24:03,960 in Python 39 under nogill in a single 649 00:24:01,620 --> 00:24:06,419 threaded uh 650 00:24:03,960 --> 00:24:09,059 um a single threaded sort of context uh 651 00:24:06,419 --> 00:24:11,880 took about 40 seconds longer to run than 652 00:24:09,059 --> 00:24:13,200 it did in Python 311 so our first useful 653 00:24:11,880 --> 00:24:14,580 lesson like if you need to make your 654 00:24:13,200 --> 00:24:16,620 code faster and you're still running 655 00:24:14,580 --> 00:24:20,280 python 310 or earlier 656 00:24:16,620 --> 00:24:22,200 upgrade to python 311 it will get faster 657 00:24:20,280 --> 00:24:22,860 for free basically 658 00:24:22,200 --> 00:24:25,440 um 659 00:24:22,860 --> 00:24:27,179 what takes even longer than running our 660 00:24:25,440 --> 00:24:29,520 single threaded version in nogill is 661 00:24:27,179 --> 00:24:30,179 running with a thread pull executor 662 00:24:29,520 --> 00:24:31,980 um 663 00:24:30,179 --> 00:24:33,480 which so instead of taking about the 664 00:24:31,980 --> 00:24:35,340 same amount of time as a single threaded 665 00:24:33,480 --> 00:24:37,700 version as it took in the Gill uh with 666 00:24:35,340 --> 00:24:42,539 the Gill it now takes about one to six 667 00:24:37,700 --> 00:24:44,520 1.6 times longer than it did in a single 668 00:24:42,539 --> 00:24:46,740 threaded execution as I was mentioning 669 00:24:44,520 --> 00:24:48,659 earlier the Gill is actually really 670 00:24:46,740 --> 00:24:50,700 really really efficient and this is why 671 00:24:48,659 --> 00:24:53,700 all these Gill removal projects have 672 00:24:50,700 --> 00:24:55,500 sort of faltered over the years 673 00:24:53,700 --> 00:24:57,659 um there's not really any slowdown from 674 00:24:55,500 --> 00:24:59,820 acquiring releasing the Gill in in 675 00:24:57,659 --> 00:25:01,980 normal python on the other hand once you 676 00:24:59,820 --> 00:25:04,500 start adding a lot more locks and things 677 00:25:01,980 --> 00:25:06,480 like finely grained thread safety into 678 00:25:04,500 --> 00:25:09,480 the the memory allocator in Python 679 00:25:06,480 --> 00:25:10,559 things get really really slow 680 00:25:09,480 --> 00:25:13,980 um 681 00:25:10,559 --> 00:25:15,840 1.6 times slower as it turns out you may 682 00:25:13,980 --> 00:25:17,600 be asking whether or not nogil is worth 683 00:25:15,840 --> 00:25:19,500 it from this one example I've given you 684 00:25:17,600 --> 00:25:22,740 first up 685 00:25:19,500 --> 00:25:25,020 yeah slowing down only 1.6 times is a 686 00:25:22,740 --> 00:25:27,179 huge Improvement on previous versions of 687 00:25:25,020 --> 00:25:29,100 trying to remove the Gill especially 688 00:25:27,179 --> 00:25:31,159 since the authors actually have an idea 689 00:25:29,100 --> 00:25:33,900 of how to make this get even faster 690 00:25:31,159 --> 00:25:36,720 secondly there are actually demos on on 691 00:25:33,900 --> 00:25:39,240 the nogill readme that demonstrates a 692 00:25:36,720 --> 00:25:41,039 CPU bound function that parallelizes 693 00:25:39,240 --> 00:25:42,179 basically with the number of cores you 694 00:25:41,039 --> 00:25:44,400 have in the number of threads you give 695 00:25:42,179 --> 00:25:46,679 it it's a really contrived example it 696 00:25:44,400 --> 00:25:48,480 doesn't touch any data structures but it 697 00:25:46,679 --> 00:25:51,840 demonstrates that you can run threaded 698 00:25:48,480 --> 00:25:54,000 python code in AC Python and get 699 00:25:51,840 --> 00:25:56,400 unbounded speed up which is which is 700 00:25:54,000 --> 00:25:58,200 very impressive there is a pep to remove 701 00:25:56,400 --> 00:25:59,760 the Gill There is a guarantee of 702 00:25:58,200 --> 00:26:02,400 sponsorship to do the real work to make 703 00:25:59,760 --> 00:26:04,080 it faster I would not be surprised if 704 00:26:02,400 --> 00:26:06,059 the Gill goes away in the next three to 705 00:26:04,080 --> 00:26:07,500 five years and that would be really 706 00:26:06,059 --> 00:26:10,140 incredible 707 00:26:07,500 --> 00:26:11,700 so to finish up we're finished talking 708 00:26:10,140 --> 00:26:13,020 about concurrency in Python let's get 709 00:26:11,700 --> 00:26:15,240 back to talking about Wordle which is 710 00:26:13,020 --> 00:26:16,620 what I'm actually interested in firstly 711 00:26:15,240 --> 00:26:19,140 all the examples I've shown you have 712 00:26:16,620 --> 00:26:20,640 been in Easy Mode I play in hard mode 713 00:26:19,140 --> 00:26:22,020 it's probably interesting to see what it 714 00:26:20,640 --> 00:26:24,179 would take to make the solver work in 715 00:26:22,020 --> 00:26:25,740 hard mode uh it's really just a matter 716 00:26:24,179 --> 00:26:28,500 of changing one line at the bottom of 717 00:26:25,740 --> 00:26:30,240 the main Loop very small so we're now 718 00:26:28,500 --> 00:26:32,940 instead of guessing with the entire set 719 00:26:30,240 --> 00:26:34,679 of English language words we're just 720 00:26:32,940 --> 00:26:37,679 solving with the set of answers that we 721 00:26:34,679 --> 00:26:39,720 get after each step and it very slightly 722 00:26:37,679 --> 00:26:41,820 changes the guesses it makes it 723 00:26:39,720 --> 00:26:43,500 significantly reduces the last the 724 00:26:41,820 --> 00:26:45,080 amount of time the subsequent guesses 725 00:26:43,500 --> 00:26:47,460 beyond the first 726 00:26:45,080 --> 00:26:49,380 takes that's because there's fewer words 727 00:26:47,460 --> 00:26:52,980 to choose from it takes less time to run 728 00:26:49,380 --> 00:26:55,159 uh cpal is the parts of the calyx of a 729 00:26:52,980 --> 00:26:55,159 flower 730 00:26:55,380 --> 00:27:01,020 and finally how good is this solver at 731 00:26:58,080 --> 00:27:03,179 actual Wordle before the New York Times 732 00:27:01,020 --> 00:27:05,340 took over the full set of answers to 733 00:27:03,179 --> 00:27:08,039 Wordle was visible in the JavaScript 734 00:27:05,340 --> 00:27:09,840 source of the game so you could you 735 00:27:08,039 --> 00:27:11,820 could basically strip that out and and 736 00:27:09,840 --> 00:27:13,140 use it as an answer list there are 737 00:27:11,820 --> 00:27:14,700 copies of this all over the Internet 738 00:27:13,140 --> 00:27:17,400 because it's the internet 739 00:27:14,700 --> 00:27:19,020 uh there's about 2 300 words in that 740 00:27:17,400 --> 00:27:21,360 answer list and we can run our solve 741 00:27:19,020 --> 00:27:22,919 against all of them firstly to establish 742 00:27:21,360 --> 00:27:25,260 a baseline let's see what the behavior 743 00:27:22,919 --> 00:27:28,380 is like if we just guess randomly from 744 00:27:25,260 --> 00:27:30,120 the set of all possible solutions it 745 00:27:28,380 --> 00:27:31,740 solves the game correctly in about 90 746 00:27:30,120 --> 00:27:33,480 percent of the time 747 00:27:31,740 --> 00:27:36,299 and there are three words that that 748 00:27:33,480 --> 00:27:37,799 trigger a bug I think this is just due 749 00:27:36,299 --> 00:27:38,940 to their not being an answer in the 750 00:27:37,799 --> 00:27:40,500 guest list and I haven't just done 751 00:27:38,940 --> 00:27:42,600 enough error correction in the code to 752 00:27:40,500 --> 00:27:45,720 account for it properly 753 00:27:42,600 --> 00:27:48,720 code first talk 754 00:27:45,720 --> 00:27:50,460 um in Easy Mode uh there's those three 755 00:27:48,720 --> 00:27:52,860 bug cases that we saw in the random 756 00:27:50,460 --> 00:27:55,320 guessing thing it successfully solves 757 00:27:52,860 --> 00:27:59,340 all but one puzzle in six guesses or 758 00:27:55,320 --> 00:28:02,039 less and it does well in more than uh it 759 00:27:59,340 --> 00:28:05,400 does well more than half of the uh of 760 00:28:02,039 --> 00:28:07,320 the words in four guesses so 761 00:28:05,400 --> 00:28:09,600 I basically play about as well as my 762 00:28:07,320 --> 00:28:11,640 solver does personally which is cool uh 763 00:28:09,600 --> 00:28:15,299 the one word that it can't guess is 764 00:28:11,640 --> 00:28:16,880 Joker it takes seven guesses uh via a 765 00:28:15,299 --> 00:28:19,380 bunch of really quite obscure words 766 00:28:16,880 --> 00:28:23,480 including aflage which is a type of 767 00:28:19,380 --> 00:28:23,480 irrigation system originating in Oman 768 00:28:24,419 --> 00:28:29,220 we can run the same exhaustive solver in 769 00:28:27,059 --> 00:28:30,720 hard mode as well and it fails to solve 770 00:28:29,220 --> 00:28:32,640 in hard mode a lot more than an easy 771 00:28:30,720 --> 00:28:33,900 mode which you've probably experienced 772 00:28:32,640 --> 00:28:35,640 if you play in hard mode yourself 773 00:28:33,900 --> 00:28:37,260 there's a lot of cases where you 774 00:28:35,640 --> 00:28:39,840 accidentally get locked into a sequence 775 00:28:37,260 --> 00:28:41,880 of equally likely answers where an 776 00:28:39,840 --> 00:28:44,100 impossible answer you know might split 777 00:28:41,880 --> 00:28:47,220 up the options so for example this this 778 00:28:44,100 --> 00:28:49,440 word curvy here if you could make the 779 00:28:47,220 --> 00:28:51,480 word if you could guess the word venz on 780 00:28:49,440 --> 00:28:53,580 the third guess you would guarantee a 781 00:28:51,480 --> 00:28:55,860 solution for those curvy Kearney Kerdi 782 00:28:53,580 --> 00:29:00,720 or you get a choice between curly and 783 00:28:55,860 --> 00:29:03,059 Curry so you get one or two guesses you 784 00:29:00,720 --> 00:29:05,039 can't use vans in hard mode because it's 785 00:29:03,059 --> 00:29:07,440 already said that S and E aren't in the 786 00:29:05,039 --> 00:29:10,080 solution so you can't use that 787 00:29:07,440 --> 00:29:12,240 um and so we failed to solve in about 91 788 00:29:10,080 --> 00:29:14,340 cases now uh there are four words and 789 00:29:12,240 --> 00:29:16,140 unless again bugs I don't know unsure 790 00:29:14,340 --> 00:29:19,559 what's going on there it manages to 791 00:29:16,140 --> 00:29:21,360 solve about 96 of cases in hard mode uh 792 00:29:19,559 --> 00:29:22,919 finally one small optimization you can 793 00:29:21,360 --> 00:29:25,980 make to the word list which is to remove 794 00:29:22,919 --> 00:29:28,020 plurals the nyt removes words that end 795 00:29:25,980 --> 00:29:31,020 in s or ES if they're plurals or 796 00:29:28,020 --> 00:29:33,179 transitive verbs it changes the opening 797 00:29:31,020 --> 00:29:36,899 guess from tears to perch which means 798 00:29:33,179 --> 00:29:38,820 lively and we now solve in 97.5 percent 799 00:29:36,899 --> 00:29:40,500 of cases but now there's seven words 800 00:29:38,820 --> 00:29:41,820 where it's uh where the answers aren't 801 00:29:40,500 --> 00:29:44,159 in the guest list 802 00:29:41,820 --> 00:29:45,899 so to recap it's reasonably easy to make 803 00:29:44,159 --> 00:29:47,940 a good word or solver it was a fun 804 00:29:45,899 --> 00:29:49,700 exercise I encourage you to do it or you 805 00:29:47,940 --> 00:29:51,899 can copy my code whichever you prefer 806 00:29:49,700 --> 00:29:54,840 threads aren't great for Wordle style 807 00:29:51,899 --> 00:29:57,720 problems but process pools are my 808 00:29:54,840 --> 00:29:59,159 sources get another word list uh which 809 00:29:57,720 --> 00:30:01,559 you can download to make your own word 810 00:29:59,159 --> 00:30:03,799 games the original version of Wordle by 811 00:30:01,559 --> 00:30:07,200 Josh Wardle for the actual answers list 812 00:30:03,799 --> 00:30:08,700 uh the uh introduction to the wordlebot 813 00:30:07,200 --> 00:30:10,679 algorithm from The New York Times They 814 00:30:08,700 --> 00:30:12,600 explain how all of that works and if you 815 00:30:10,679 --> 00:30:14,039 want to read my own code and point and 816 00:30:12,600 --> 00:30:16,559 poke holes at it 817 00:30:14,039 --> 00:30:18,740 it's available on my GitHub thanks 818 00:30:16,559 --> 00:30:18,740 everyone 819 00:30:21,480 --> 00:30:23,600 thank you