title: File download with concurrent.futures or multiprocessing - How to stop on Ctrl-C?
body: <p>I've read a lot of questions on SO and elsewhere on this topic but can't get it working. Perhaps it's because I'm using Windows, I don't know.</p>
  
  <p>What I'm trying to do is download a bunch of files (whose URLs are read from a CSV file) in parallel. I've tried using <code>multiprocessing</code> and <code>concurrent.futures</code> for this with no success. </p>
  
  <p>The main problem is that I can't stop the program on Ctrl-C - it just keeps running. This is especially bad in the case of processes instead of threads (I used <code>multiprocessing</code> for that) because I have to kill each process manually every time.</p>
  
  <p>Here is my current code:</p>
  
  <pre><code>import concurrent.futures
  import signal
  import sys
  import urllib.request
  
  class Download(object):
    def __init__(self, url, filename):
      self.url = url
      self.filename = filename
  
  def perform_download(download):
    print('Downloading {} to {}'.format(download.url, download.filename))
    return urllib.request.urlretrieve(download.url, filename=download.filename)  
  
  def main(argv):
    args = parse_args(argv)
    queue = []
    with open(args.results_file, 'r', encoding='utf8') as results_file:
      # Irrelevant CSV parsing...
      queue.append(Download(url, filename))
  
    def handle_interrupt():
      print('CAUGHT SIGINT!!!!!!!!!!!!!!!!!!!11111111')
      sys.exit(1)
  
    signal.signal(signal.SIGINT, handle_interrupt)
  
    with concurrent.futures.ThreadPoolExecutor(max_workers=args.num_jobs) as executor:
      futures = {executor.submit(perform_download, d): d for d in queue}
      try:
        concurrent.futures.wait(futures)
      except KeyboardInterrupt:
        print('Interrupted')
        sys.exit(1)
  </code></pre>
  
  <p>I'm trying to catch Ctrl-C in two different ways here but none of them works. The latter one (<code>except KeyboardInterrupt</code>) actually gets run but the process won't exit after calling <code>sys.exit</code>.</p>
  
  <p>Before this I used the <code>multiprocessing</code> module like this:</p>
  
  <pre><code>try:      
      pool = multiprocessing.Pool(processes=args.num_jobs)
      pool.map_async(perform_download, queue).get(1000000)
    except Exception as e:
      pool.close()
      pool.terminate()
      sys.exit(0)
  </code></pre>
  
  <p>So what is the proper way to add ability to terminate all worker threads or processes once you hit Ctrl-C in the terminal?</p>
  
  <p>System information:</p>
  
  <ul>
  <li>Python version: 3.6.1 32-bit</li>
  <li>OS: Windows 10</li>
  </ul>