2019-02-05T18:39:12Z
Requests waiting for a slot to be free. I am stuck with selenium. Hope you can help me out. We set up selenium in kubernetes cluster. 1 selenium hub (3.141.59) - official docker Image. First- I sat in my car for nearly 2 hours trying to get this to connect. I dont have bluetooth, so the obvious appeal is that I can now have a wonderful hands-free option, and Alexa to boot! However- 2 hours, and nothing. Blue lights, zero response. Unplugged, replugged, restarted, nothing. I waited for my husband to come home before going postal.
For many types of applications, at times it is necessary to pause the running of the program until some external condition occurs. You may need to wait until another thread finishes, or maybe until a new file appears in a directory on disk that is being watched.
In these and many other situations you will need to figure out a way to make your script wait, and this isn't as easy as it sounds if you want to do it properly! In this article I'm going to show you a few different ways to wait. I'm going to use Python for all the examples, but the concepts I'm going to present apply to all programming languages.
An Example Application That Waits
To show you these wait patterns, I'm going to use an example application, shown below:
In this application, the background_calculation()
function performs some computation that is slow. To keep this example simple, I have coded this function with a time.sleep()
call with a random time of up to 5 minutes. When the function reaches the end, a result
global variable is set with the result of this made-up calculation, which is going to be, obviously, the number forty-two.
The main application function starts the background calculation in a separate thread, then waits for the thread to complete its work and finally prints the result
global variable. The version of this function that you see above does not have the waiting part implemented, you can see a TODO
comment in the place where the wait needs to take place. In the following sections I'm going to show you a few different ways to implement this wait, starting from the worst and working my way up to the best.
The Ugly: Busy Waiting
The easiest and most intuitive way to perform this wait is to use a while-loop:
If you want to try this, here is the complete script that you can copy/paste:
This is a really bad way to wait. Can you tell why?
If you want to experience it, you can try the script on your system. As soon as the script runs, open your Task Manager on Windows, Activity Monitor on Mac or maybe top
if you prefer the command line. Look at CPU usage and note how it goes through the roof.
This while-loop appears to be an empty loop, and in fact it mostly is, with the only exception that the loop exit condition needs to be checked over and over again to determine when the loop should exit. So while the loop body is completely empty, Python is forced to continuously evaluate result is None
, and actually, the fact that the loop is empty makes Python concentrate fully on repeating this evaluation as fast as it possibly can, burning a lot of CPU cycles, and making everything else running on that CPU much slower!
This type of wait loop is often called a busy wait. And a CPU that is stuck doing a lot of work over nothing as in this case is said to be spinning. Never do this.
The Bad: Busy Waiting With Sleep
It is interesting that in the busy waiting example from the previous section, you would think that having an empty loop should give less work to the CPU, but in fact the contrary happens. So the obvious improvement to the previous solution is to add something inside the while-loop that puts a brake to the CPU frantically evaluating the while-loop exit condition.
I'm sure a lot of you can guess what we can do inside the loop to slow things down a bit. We can sleep:
Here is the entire script, in case you want to run it locally:
The time.sleep()
function will suspend the execution for the number of seconds passed in the argument. In the above example, we are sleeping for 15 seconds in each loop iteration, which means that Python will only evaluate the exit condition of the loop at a rate of four times per minute, compared to as fast as it could in the previous version. During those 15 seconds of sleep the CPU will not perform any work, and will be free to take on work from other processes running on your computer.
If you try this version of the wait, you are going to find that the script waits without overtasking the CPU, so you may think that we now have the perfect solution. Yet, I have titled this section 'The Bad', didn't I?
While this solution is miles better than the previous one, there are two problems with it that still make it less than ideal. First of all, this loop still qualifies as busy waiting. It uses a lot less CPU than the previous one, but we still have a CPU that is spinning. We just made it tolerable by reducing the frequency of the spin.
The second problem is more concerning, in my opinion. Imagine the background task that is doing this calculation takes exactly 61 seconds to complete its work and produce a result. If our wait loop starts at about the same time the task starts, it would be checking the value of the result
variable at 0, 15, 30, 45, 60 and 75 seconds. The check at 60 seconds would still return False
because the background task still has one more second to go, so it will be the check at 75 seconds the causes the loop to exit. Can you see the problem? The loop exited at 75 seconds, but the background task finished at 61, so the wait extended for an extra 14 seconds!
While this type of wait is very common, it has this 'resolution' problem, where the length of the wait is a multiple of the amount of sleep you do inside the loop. If you sleep less, then your wait time will be more accurate, but your CPU usage will go up due to busy waiting. If you sleep more, then you use less CPU, but you may end up waiting much longer than needed.
The Good #1: Joining the Thread
Let's say that we want our wait to be as efficient as possible. We want the wait to be over at the exact moment the result is produced by the calculation thread. How can we do that?
Solutions implemented just with Python logic like the previous two are not going to work, because to determine if the thread finished we need to run some Python code. If we run the check too often we use a lot of CPU, and if we run it not too often we will miss the exact moment the thread completed. We've seen this clearly in the previous two sections.
To be able to wait efficiently, we need external help from the operating system, which can efficiently notify our application when certain events occur. In particular, it can tell us when a thread exits, an operation that is called joining a thread.
The threading.Thread
class from the Python standard library has a join()
method that will return at the exact moment the thread exits:
And here is the complete script:
The join()
call blocks in the same way as time.sleep()
, but instead of blocking for a fixed amount of time, it is going to block while the background thread runs. At the exact moment the thread finishes, the join()
function is going to return, and the application can continue. The operating system makes doing an efficient wait a lot easier!
The Good #2: Waiting on an Event
2 Requests Waiting For A Slot To Be Free Download
If you need to wait for a thread to finish, the pattern I presented in the previous section is what you should use. But of course, there are many other situations in which you may need to wait for things other than threads, so how do you wait for some sort of ordinary event not tied to a thread or other operating system resource?
To show you how to do this, I'm going to modify the background thread in the example I've been using and make a bit more complex. This thread is still going to produce a result, but it is not going to exit immediately after that, it will continue running and doing some more work:
If you run the above version of the example, the result is going to be reported 10 seconds late, because the thread remains running for that long after generating the result. But of course we want to report the result at the exact moment it is available.
For situations like these, where you need to wait on an arbitrary condition, we can use an Event
object, which comes in the threading
package from the Python standard library. Here is how to create an event:
Events have a wait()
method, which we will use to write our wait:
The difference between the Event.wait()
and Thread.join()
methods is that the latter is pre-programmed to wait for a specific event, which is the end of a thread. The former is a general purpose event that can wait on anything. So if this event object can wait on any condition, how do we tell it when to end the wait? For that, the event object has a set()
method. Immediately after the background thread sets the result
global variable it can set the event, causing any code waiting on it to unblock:
Here is the complete code for this example:
So here you can see how the background thread and the main thread are synchronized around this Event
object.
The Good #3: Waiting While Displaying a Progress Percentage
One great thing about event objects is that they are general purpose, so you are going to find a lot of situations in which they can be useful if you apply a little bit of creativity. For example, consider this common pattern when writing a background thread function:
Here we are trying to write a thread that can be terminated gracefully by setting the exit_thread
global variable to True
. This is a pretty common pattern, but by now you can probably identify why this isn't a great solution, right? It can take up to 10 seconds from the time the exit_thread
variable is set until the thread actually exits, and that is without counting the extra time that may pass until the thread reaches the sleep statement.
We can write this in a much more efficient way using an Event
object, taking advantage of the timeout
argument that can be passed into the Event.wait()
method:
With this implementation we have replaced a fixed-time sleep with a smart wait on an event object. We are still sleeping for 10 seconds at the end of each iteration, but if the thread is stuck in the exit_thread.wait(timeout=10)
call at the exact moment the event's set()
method is called from somewhere else, then the call will promptly return True
and the thread will exit. If the timeout of 10 seconds is reached, then the wait()
call returns False
and the thread continues running the loop, so it is the same result as calling time.sleep(10)
.
If some other part of the program calls exit_thread.set()
at a time where the thread is doing some work inside the loop, then the thread will continue running, but as soon as it reaches the exit_thread.wait()
call it will return True
immediately and exit. The secret to be able to terminate the thread without having to wait a lot is to make sure the event object is checked often enough.
Let me show you one more complete example using this timeout
argument. What I'm going to do is take the code from the previous section and expand it to show a completion percentage while the wait is taking place.
First, let's add progress reporting to our background thread. In the original version, I slept for a random number of seconds up to a maximum of 300, which is 5 minutes. To report task progress during this time I'm going to replace the single sleep with a loop that runs 100 iterations sleeping a little bit in each, and this will give me the opportunity to report a progress percentage in each iteration. Since the big sleep went for up to 300 seconds, now I'm going to do 100 sleeps of up to 3 seconds each. Overall, this task will take the same amount of random time, but having the work partitioned in 100 pieces makes it easy to report a completion percentage.
Here are the changes to the background thread to report progress percentages in a progress
global variable:
And now we can build a more intelligent wait that reports the percentage of completion every 5 seconds:
This new while loop is going to wait for the result_available
event for up to 5 seconds as an exit condition. If nothing happens during this interval, then wait()
is going to return False
and we get inside the loop, where the current value of the progress
variable is printed. Note that I use the r
character and the end=', flush=True
arguments to the print()
function to prevent the terminal from jumping to the next line. This trick allows you to print and reprint the same terminal line, so each progress line will print on top of the previous one.
As soon as the background calculation calls set()
on the event object the loop is going to exit because wait()
will immediately return True
, and at this point I issue one more print, this time with the default end of line, so that I get the final percentage printed and the terminal is left ready to print the result on the next line.
Here is the complete code, if you want to run it or study it in more detail:
More Ways to Wait!
2 Requests Waiting For A Slot To Be Free Play
Event objects are not the only way to wait for events in your application, there are more ways, some of which may be more appropriate than events, depending on what you are waiting for.
If you need to watch a directory for files and act on the files as they are dropped there or when existing files are modified, an event is not going to be useful because the condition that should set the event is external to the application. In this case you need to use facilities provided by the operating system to watch for file system events. In Python, you can use the watchdog package, which wraps a few file watching APIs available in different operating systems.
If you need to wait for a subprocess to end, the subprocess package provides some functions to launch and wait for processes.
If you need to read from a network socket, the default configuration of the socket will make your read block until data arrives, so this works well as an efficient wait. If you need to wait on data arriving on multiple sockets or other file descriptors, then the select package from the Python standard library contains wrappers for operating system functions that can do this waiting efficiently.
If you want to write applications that produce and/or consume items of data, then you can use a Queue object. The producer adds items to the queue, while the consumer efficiently waits for items to take from it.
As you can see, in most cases, the operating system provides efficient wait mechanisms, so all you need to do is find how to access those from Python.
Waiting in Asyncio
If you are using the asyncio
package, then you have access to similar types of waiting functions. For example, there are asyncio.Event and asyncio.Queue objects that are modeled after the original ones in the standard library, but based on the async/await style of programming.
Conclusion
I hope this article motivates you to think more carefully about how you wait in your applications. I suggest you play with all the examples I provided to familiarize with these techniques and eventually use them to replace inefficient time.sleep()
calls in your code!
Hello, and thank you for visiting my blog! If you enjoyed this article, please consider supporting my work on this blog on Patreon!
30 comments
#1Viktor said 2019-02-05T23:26:22Z
#2Miguel Grinberg said 2019-02-05T23:33:41Z
#3Jair said 2019-02-06T19:51:27Z
#4Affa said 2019-02-12T00:27:11Z
#5bryan said 2019-02-13T20:50:57Z
#6Miguel Grinberg said 2019-02-13T23:42:59Z
#7Alvaro said 2019-06-30T16:45:47Z
#8Vinod said 2019-07-24T04:16:14Z
#9Avi said 2019-12-20T18:13:21Z
#10Pedro Rivera said 2019-12-20T20:00:23Z
#11Miguel Grinberg said 2019-12-21T16:37:28Z
#12karl said 2019-12-24T23:13:14Z
#13Manuel Souto Pico said 2020-02-17T18:07:02Z
#14Miguel Grinberg said 2020-02-17T23:02:54Z
#15Igor Sousa Silva said 2020-02-23T17:14:06Z
#16Miguel Grinberg said 2020-02-23T23:00:04Z
#17Igor Sousa Silva said 2020-03-06T06:06:39Z
#18Miguel Grinberg said 2020-03-06T10:24:22Z
#19Maanas said 2020-03-08T19:56:49Z
#20Thierry Caiheton said 2020-04-06T11:07:20Z
#21Jeff said 2020-04-12T17:03:14Z
#22Bennett Gould said 2020-08-03T17:21:10Z
#23Miguel Grinberg said 2020-08-03T20:39:18Z
#24ak said 2020-09-29T01:36:50Z
#25Miguel Grinberg said 2020-09-29T07:47:14Z
Leave a Comment
So you are looking to schedule a meeting with someone you don’t know very well…
- What is the correct protocol to ask for a meeting?
- How do you get the meeting without seeming like a jerk?
- What if they turn you down?
These questions can cause you anxiety, especially if you’re an introvert who is not good at talking to new people (like me).
Below are my tips for how I approach getting a meeting with someone new:
How To Get A Meeting
1. Have Context
I generally avoid asking someone for a meeting that I don’t have context for. I define “context” as a point of reference… either you met them at an event, or you know someone who knows them, or you’re a big fan. Context is anything reason valuable enough for you to reach out to them.
Request a follow-up meeting on the spot
2 Requests Waiting For A Slot To Be Free To Play
If I talk to someone at an event, I try to get a follow up while the conversation is still fresh.
Example: “I would love to chat more about ABC, would you be interested in grabbing coffee or lunch sometime this week?” If possible pull your phone out and send a meeting invite right away.
Write a note their business card
Make sure you write some information about the discussion on the back of the card to refresh your memory if you send out an invite later on. When you send out an email after an event, be sure to mention where you met them and what you discussed, e.g. “It was great meeting you at the fundraiser on Friday. I enjoyed chatting with you about ABC. Per our discussion, I would love to grab a meeting this week to chat more about ABC.”
Find mutual friends or contacts
LinkedIn can be pretty useful for figuring out who knows who. If someone you know has a connection with the person, don’t be afraid to ask them for an intro. e.g. “Hey Jamie, I am looking to reach out to Kris Smith to pick his brain about mobile UX. His presentation on his blog really resonated with me. I saw on LinkedIn you are connected to him. Would you be able to introduce me?”
The key is giving them a sense of why you want to talk to the person and allow them to filter the information in advance of introducing yourself. The more details the better. This will allow them to provide as much information as possible.
Important: Do not burn someone who referred you. If someone refers you and you piss off their connection, they may never refer you to someone again.
You’re a “fan” of their work
Being a fan of someone’s work can be flattering, but it can also come across kinda creepy. I would recommend having a strong reason to reach out to someone if you’re a fan. If you aren’t able to meet the person at an event or get a referral, you have to go with the old “cold request”.
When you send a cold request, you need to be very clear about why you want to meet them. If you send an email that reads: “Hey, I would like to have a meeting with you. Thanks!” – you probably won’t get a response. Your intro should be very clearly crafted.
Example: “Hi Kris, My name is Brett Cooper and I do mobile dev work on iOS projects for a company here in Atlanta. I saw you speak last year at Web Afternoon, and I really enjoyed your presentation. I was wondering if could buy you lunch and pick your brain about a mobile problem that I’m looking to solve around multi-screen size format. Do you have any availability this Thursday or Friday? Thanks!”
2. Scheduling the meeting
So they respond back to your meeting request with “Sure, what time do you want to meet?” Your objective is to quickly get something set on the calendar.
- The calendar game – My rule of thumb is to ask for 2-3 time slots within the next 5 days. If they can’t meet any of the time slots, ask them for some alternatives.
- Target the morning – Try to get something first thing in the morning (e.g. a coffee meeting) so you are less likely to get bumped because one of their other meetings ran late.
- If all else fails, try the phone – If you are struggling to get something scheduled, ask if you can do a quick 90-second phone call to resolve calendar alignment issues.
- Pick a specific location – Try and pick a specific location near where they work or ask them if it would be most convenient to meet at their office. The more specific you are in the request, the more likely it will be to that you successfully schedule the meeting.
- Use helpful tools – There are a lot of tools out there that try to solve the scheduling puzzle. I would take a look at Calendly, Bookeo, or Acuity if you are trying to schedule a lot of meetings. These tools can be very useful for larger groups, but I would stick with emails and the phone for 1:1 meeting scheduling.
- Try A.I. – Recently I tried out https://x.ai which offers a virtual personal assistant AI that will work to look at your calendar and coordinate with multiple other parties to finalize a meeting time. The experience was pretty smooth, but it did still require 2-3 emails to get the meeting finalized. Another more recent entrant in the AI assistant field is MeetSally.eu. I have no doubt that AI meeting assistants will continue to get better over the next few years.
- The invite format– When you schedule a meeting, send out a calendar invite to make sure each attendees time gets blocked on their calendars.
The key things you should include in a meeting invite are:
- Title – the Title of the meeting invite should be clear on what the meeting is about.
- Location – Include the location in both the location field and body/comments. Preferably the address if you are driving there.
- Summary – Have a summary of the meeting request in the body.
- Objective – Clearly state the objective of the meeting.
- Agenda – When you send a meeting invite, make sure to have a clear agenda (with some time-boxing). Thinking about the agenda and time boxes ahead of time will help you get a clearer picture of what you want to talk about and whether you actually have enough time to cover everything.
- Notification – Be sure to include a notification equal to the amount of travel time (or 5 minutes if it doesn’t require travel).
- Contact – Include your cell phone and their cell number (if possible). This makes it easy for them to reach you if they are running late.
Here is an example of a meeting invite.
Title: Cooper / Kris Meeting to talk about Mobile UX Challenges Attendees: Brett Cooper, Kris K. Location: Octane Coffee Emory Village Reminder: 15 minutes before Body: Kris, Per our email discussion, I would like to grab a coffee and pick your brain on mobile UX topics Objective: Discuss mobile UX challenges on iOS vs Android Agenda:
Contact: Brett’s cell: 855-529-6349 |
3. Follow-up After the Meeting
Having a post-meeting reason to discuss things is a good way to build a long term relationship or conversation.
Send a thank you email – Send a note thanking the person for meeting with you. I will also typically include any meeting notes and any action items that I took away from the meeting. I know some people who send classy hand-written thank you notes, but I have the worst handwriting… so I normally stick with an email thank you.
Try to followup within 2-5 days – Try to follow up with any actions you had within a week of the meeting. You want to show that you were seriously paying attention and valued their help and input.
Offer reciprocal help – Be sure to offer your reciprocal help if they helped you with something. Keep it simple: “ Tina, Thanks for your recommendations on sales frameworks, this will really help me out. I owe you one. Let me know if I can help you with anything.”
Leave the door open for next steps – If someone gives you advice about a situation or challenge you are facing, have a followup status that you send them in the future to show how you resolved it or how it played out.
General Expectations
- Mail 2-3 times before you give up. More than 3 times verges on stalking, annoying, desperate, or even worse… being a sales guy.
- Don’t expect someone to work miracles for you.
- Time is a very valuable commodity, don’t waste someone else’s time.
- Get out and meet people, build valuable relationships, and help other people out… it will eventually come around to you.
- Be grateful. Life is full of people who are looking to help out where they can. Be thankful even for small amounts of help.
Whats the Worst That Can Happen?
It’s not easy to reach out to people you don’t know to schedule a meeting. The worst thing that can typically happen is that they will ignore you. I have never had someone get angry at me when I reached out to them for a good reason… I image that if they did get angry they are not the type of person I want to be meeting with anyway.
Practive the above steps and it will be easier to schedule meetings with people you don’t know.