title: Some doubts about Thread Pool Executor and Thread in python
body: <p>Recently,I tried to use asyncio to execute multiple blocking operations asynchronously.I used the function <code>loop.run_in_executor</code>,It seems that the function puts tasks into the thread pool.As far as I know about thread pool,it reduces the overhead of creating and destroying threads,because it can put in a new task when a task is finished instead of destroying the thread.I wrote the following code for deeper unstanding.</p>
  
  <pre><code>def blocking_funa():
      print('starta')
      print('starta')
      time.sleep(4)
      print('enda')
  def blocking_funb():
      print('startb')
      print('startb')
      time.sleep(4)
      print('endb')
  loop = asyncio.get_event_loop()
  tasks = [loop.run_in_executor(None, blocking_funa), loop.run_in_executor(None, blocking_funb)]
  loop.run_until_complete(asyncio.wait(tasks))
  </code></pre>
  
  <p>and the output:</p>
  
  <pre><code>starta
  startbstarta
  
  startb
  (wait for about 4s)
  enda
  endb
  </code></pre>
  
  <p>we can see these two tasks are almost simultaneous.now I use threading module:</p>
  
  <pre><code>threads = [threading.Thread(target = blocking_ioa), threading.Thread(target = blocking_iob)]
  for thread in threads:
      thread.start()
      thread.join()
  </code></pre>
  
  <p>and the output:</p>
  
  <pre><code>starta
  starta
  enda
  startb
  startb
  endb
  </code></pre>
  
  <p>Due to the GIL limitation, only one thread is executing at the same time，so I understand the output.But how does thread pool executor make these two tasks almost simultaneous.What is the different between thread pool and thread?And Why does thread pool look like it's not limited by GIL?</p>