A brief explanation of the thread problem in Python and a description of the python thread

Source: Internet
Author: User

A brief explanation of the thread problem in Python and a description of the python thread

We will see some examples of using threads in Python and how to avoid competition between threads. You should run the following example multiple times so that you can notice that the thread is unpredictable and different results are produced each time the thread runs. Disclaimer: Forget about GIL from here, because GIL will not affect what I want to display.

Example 1

We will request five different urls:
Single thread
 

import timeimport urllib2 def get_responses(): urls = [  'http://www.google.com',  'http://www.amazon.com',  'http://www.ebay.com',  'http://www.alibaba.com',  'http://www.reddit.com' ] start = time.time() for url in urls:  print url  resp = urllib2.urlopen(url)  print resp.getcode() print "Elapsed time: %s" % (time.time()-start) get_responses()

The output is:
 

http://www.google.com 200http://www.amazon.com 200http://www.ebay.com 200http://www.alibaba.com 200http://www.reddit.com 200Elapsed time: 3.0814409256

Explanation:

  • Request in url order
  • The cpu does not request the next url unless it returns a response from a url.
  • Network requests take a long time, so the cpu remains idle for the time the network request returns.

Multithreading
 

import urllib2import timefrom threading import Thread class GetUrlThread(Thread): def __init__(self, url):  self.url = url  super(GetUrlThread, self).__init__()  def run(self):  resp = urllib2.urlopen(self.url)  print self.url, resp.getcode() def get_responses(): urls = [  'http://www.google.com',  'http://www.amazon.com',  'http://www.ebay.com',  'http://www.alibaba.com',  'http://www.reddit.com' ] start = time.time() threads = [] for url in urls:  t = GetUrlThread(url)  threads.append(t)  t.start() for t in threads:  t.join() print "Elapsed time: %s" % (time.time()-start) get_responses()

Output:
 

http://www.reddit.com 200http://www.google.com 200http://www.amazon.com 200http://www.alibaba.com 200http://www.ebay.com 200Elapsed time: 0.689890861511

Explanation:

  • Realized the improvement of program execution time
  • We have written a multi-threaded program to reduce the cpu wait time. When we are waiting for a network request in a thread to return, the cpu can switch to another thread for network requests in other threads.
  • We expect a thread to process a url, So we pass a url when instantiating the Thread class.
  • Thread running means the run () method in the execution class.
  • In any case, we want each thread to execute run ().
  • Create a thread for each url and call the start () method, which indicates that the cpu can execute the run () method in the thread.
  • The join () method is called because we want all threads to calculate the time consumed when execution is complete.
  • Join () can notify the main thread to wait until the end of this thread before the next instruction can be executed.
  • We call the join () method for each thread, So we calculate the running time after all threads are executed.

Thread:

  • The cpu may not execute the run () method immediately after calling start.
  • You cannot determine the execution sequence of run () between different threads.
  • For a separate thread, you can ensure that the statements in the run () method are executed in order.
  • This is because the url in the thread is requested first and then the returned result is printed.

Instance 2

We will use a program to demonstrate the resource competition among multiple threads and fix this problem.
 

from threading import Thread #define a global variablesome_var = 0 class IncrementThread(Thread): def run(self):  #we want to read a global variable  #and then increment it  global some_var  read_value = some_var  print "some_var in %s is %d" % (self.name, read_value)  some_var = read_value + 1  print "some_var in %s after increment is %d" % (self.name, some_var) def use_increment_thread(): threads = [] for i in range(50):  t = IncrementThread()  threads.append(t)  t.start() for t in threads:  t.join() print "After 50 modifications, some_var should have become 50" print "After 50 modifications, some_var is %d" % (some_var,) use_increment_thread()

Run this program multiple times and you will see a variety of different results.

Explanation:

  • There is a global variable that all threads want to modify.
  • All threads should add 1 to the global variable.
  • There are 50 threads, and the final value should be 50, but it does not.

Why didn't it reach 50?

  • When some_var is 15, thread t1 reads some_var. At this time, the cpu gives control to another thread t2.
  • Some_var read by thread t2 is also 15
  • Both t1 and t2 add some_var to 16
  • What we expected at the time was that the two t1 t2 threads changed some_var + 2 to 17.
  • Here there is resource competition.
  • The same situation may also occur between other threads, so the final result is less than 50.

Solving Resource Competition
 

from threading import Lock, Threadlock = Lock()some_var = 0 class IncrementThread(Thread): def run(self):  #we want to read a global variable  #and then increment it  global some_var  lock.acquire()  read_value = some_var  print "some_var in %s is %d" % (self.name, read_value)  some_var = read_value + 1  print "some_var in %s after increment is %d" % (self.name, some_var)  lock.release() def use_increment_thread(): threads = [] for i in range(50):  t = IncrementThread()  threads.append(t)  t.start() for t in threads:  t.join() print "After 50 modifications, some_var should have become 50" print "After 50 modifications, some_var is %d" % (some_var,) use_increment_thread()

Run this program again to achieve our expected results.

Explanation:

  • Lock is used to prevent competition conditions.
  • If thread t1 obtains the lock before performing some operations. Other threads do not perform the same operation before t1 releases Lock.
  • What we want to determine is that once thread t1 has read some_var, it will not be able to read some_var until T1.
  • In this way, some_var is read and modified as an atomic operation in logic.

Instance 3

Let's use an example to prove that a thread cannot affect the variables (non-global variables) in other threads ).

Time. sleep () can suspend a thread and force thread switching.
 

from threading import Threadimport time class CreateListThread(Thread): def run(self):  self.entries = []  for i in range(10):   time.sleep(1)   self.entries.append(i)  print self.entries def use_create_list_thread(): for i in range(3):  t = CreateListThread()  t.start() use_create_list_thread()

After running the command several times, the result is not printed. When a thread is being printed, the cpu switches to another thread, which leads to incorrect results. We need to ensure that print self. entries is a logical atomic operation to prevent printing from being interrupted by other threads.

We use Lock () to see the example below.
 

from threading import Thread, Lockimport time lock = Lock() class CreateListThread(Thread): def run(self):  self.entries = []  for i in range(10):   time.sleep(1)   self.entries.append(i)  lock.acquire()  print self.entries  lock.release() def use_create_list_thread(): for i in range(3):  t = CreateListThread()  t.start()

use_create_list_thread()

This time we see the correct results. It proves that a thread cannot modify the internal variables (non-global variables) of other threads ).

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.