3

I am getting really confused here about multithreading :( I am reading about the C# Async/Await keywords. I often read, that by using this async feature, the code gets executed "non-blocking". People put code examples in two categories "IO-Bound" and "CPU-bound" - and that I should not use a thread when I execute io-bound things, because that thread will just wait ..

I dont get it... If I do not want a user have to wait for an operation, I have to execute that operation on another thread, right ?

If I use the Threadpool, an instance of "Thread"-class, delegate.BeginInvoke or the TPL -- every asynchronous execution is done on another thread. (with or without a callback)

Erik Mandke
  • 1,577
  • 3
  • 23
  • 30
  • 2
    Threads are one way to achieve asynchrony, but asynchrony does not require the use of threads. See Stephen Cleary's article, [There is No Thread](http://blog.stephencleary.com/2013/11/there-is-no-thread.html). – Mike Zboray May 03 '15 at 17:52
  • MS has actually done a pretty decent job in documenting this. Not sure if you've read the Asynchronous Programming guide... but you should: https://msdn.microsoft.com/en-us/library/hh191443.aspx – B.K. May 03 '15 at 17:54
  • Also, for a very good introduction to threading in c# you may want to read this http://www.albahari.com/threading/ – Alex May 03 '15 at 18:01

3 Answers3

5

What you are missing is that not every asynchronous operation is done on another thread. Waiting on an IO operation or a web service call does not require the creation of a thread. On Windows this is done by using the OS I/O Completion Ports.

What happens when you call something like Stream.ReadAsync is that the OS will issue a read command to the disk and then return to the caller. Once the disk completes the read the notifies the OS kernel which will then trigger a call back to your processes. So there is no need to create a new threadpool thread that will just sit and block.

shf301
  • 31,086
  • 2
  • 52
  • 86
  • Interesting - I've been working with Windows all my life (that's the way it feels) and I was unaware of I/O Completion Ports. A bit of Googling found this: http://stackoverflow.com/questions/5283032/i-o-completion-ports-advantages-and-disadvantages – RenniePet May 03 '15 at 18:04
  • So .. with those I/O Completion Ports.. Can I write my own method use those.. like MyClass.DoSomethingAsyncWithoutUsingThreads() ? – Erik Mandke May 03 '15 at 18:04
  • I/O Completion Ports are a kernel service, so you would have to write driver level code to publish one. Anyway it wouldn't do you any good unless you had a hardware or network device to talk to. If you want to run code then you need a thread. The I/O completion ports are only for I/O. If you want to use the CPU you need a thread. – shf301 May 03 '15 at 18:11
  • So if I have io-bound code I better use the "..Async"-methods, because they do use the io completion ports. – Erik Mandke May 03 '15 at 18:14
  • In general yes. A thread isn't free it takes some memory and OS resources to manage, not to mention the cost for a CPU to switch between threads.. In a client application with one or two I/O requests it may not make a huge difference, but on a server with a lot of clients it can be huge. – shf301 May 03 '15 at 18:18
2

What is meant is this:

Suppose you query some data from a database (on another server) - you will send a request and just wait for the answer. Instead of having a thread block and wait for the return it's better to register an callback that get's called when the data comes back - this is (more or less) what async/await does. It will free the thread to do other things (give it back to the pool) but once your data come back asynchronously it will get another thread and continue your code at the point you left (it's really some kind of state-machine that handles that).

If your calculation is really CPU intensive (let's say you are calculating prime-numbers) things are different - you are not waiting for some external IO, you are doing heavy work on the CPU - here it's a better idea to use a thread so that your UI will not block.

Random Dev
  • 51,810
  • 9
  • 92
  • 119
1

I dont get it... If I do not want a user have to wait for an operation, I have to execute that operation on another thread, right ?

Not exactly. An operation will take however long it is going to take. When you have a single-user application, running long-running things on a separate thread lets the user interface remain responsive. At the very least this allows the UI to have something like a "Cancel" button that can take user input and cancel processing on the other thread. For some single-user applications, it makes sense to allow the user to keep doing other things while a long-running task completes (for example let them work on one file while another file is uploading or downloading).

For web applications, you do not want to block a thread from the thread pool during lengthy(ish) IO, for example while reading from a database or calling another web service. This is because there are only a limited number of threads available in the thread pool, and if they are all in use, the web server will not be able to accept additional HTTP requests.

Eric J.
  • 147,927
  • 63
  • 340
  • 553