Understanding Threads in Python

Source: Internet
Author: User
We will see some instances of using threads in Python and how to avoid the competition between threads.

You should run the example below several times so that you can notice that the thread is unpredictable and that the threads run out of different results each time. Disclaimer: Start by forgetting what you've heard about Gil, because Gil doesn't affect what I want to show.

Example 1

We are going to request five different URLs:

Single Thread

Import Timeimport urllib2def 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

Explain:

    • The URL order is requested


    • The next URL is not requested unless the CPU receives a response from a URL


    • Network requests take a long time, so the CPU is idle for the return time of the network request.

Multithreading

Import urllib2import timefrom Threading Import ThreadClass 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

Explain:

    • Aware of the program's improvement in execution time


    • We wrote a multithreaded program to reduce CPU wait times, and when we waited for a network request to return within a thread, the CPU could switch to another thread to make a network request within another thread.


    • We expect a thread to process a URL, so when we instantiate the thread class we pass a URL.


    • Running a thread means executing the method in the class run() .


    • Anyway we want each thread to have to execute run() .


    • Create a thread for each URL and invoke the start() method, which tells the CPU to execute the method in the thread run() .


    • We want to calculate the time spent when all the threads have finished executing, so we call the join() method.


    • join()You can tell the main thread to wait for the thread to finish before you can execute the next instruction.


    • Each thread we call the join() method, so we are calculating the elapsed time after all the threads have finished executing.

About Threads:

    • The CPU may not start() execute the method immediately after the call run() .


    • You cannot determine the run() order of execution between different line Chengjian.


    • For a single thread, the run() statements in the method are guaranteed to be executed sequentially.


    • This is because the URL inside the thread is requested first, and then the returned result is printed out.

Example 2

We will use a program to demonstrate the resource competition between 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 was%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:        t = incrementthread () 
  threads.append (t)        T.start ()    for T in Threads:        t.join ()    print "After modifications, some_ var should has become "    print" after the modifications, Some_var is%d "% (Some_var,) Use_increment_thread ()

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

Explain:

    • There is a global variable, and all threads want to modify it.


    • All threads should add 1 to this global variable.


    • There are 50 threads, and the last value should be 50, but it doesn't.

Why not reach 50?

    • At some_var that 15 time, the thread t1 reads some_var , and at this point the CPU gives control to the other thread t2 .


    • t2The thread reads the some_var same15


    • t1and t2 all some_var add to16


    • At the time we were expecting t1 t2 two threads to some_var + 2 turn into a17


    • There is a competition for resources here.


    • The same situation can occur between other threads, so there is a case where the final result is less 50 .

Resolving resource Competition

From threading import Lock, Threadlock = Lock () Some_var = 0 Class Incrementthread (Thread):    def run:        #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 was%d"% (Self.name, read_value)        Some_var = read_value + 1         print "Some_var in%s after Inc Rement is%d "% (Self.name, Some_var)        lock.release () def use_increment_thread ():    threads = [] for    I in range (a):        t = incrementthread ()        threads.append (t)        T.start () for    T in Threads:        t.join ()    Print "After modifications, Some_var should has become"    print "after modifications, Some_var is%d"% (some _var,) Use_increment_thread ()

Run the program again to achieve the results we expect.

Explain:

    • Lock is used to prevent competitive conditions


    • If a thread obtains a lock before performing some action t1 . Other threads do t1 not perform the same operation until Lock is released


    • What we want to make sure is that once the thread t1 has been read some_var , the t1 some_var other threads can read it until the modification is complete.some_var


    • This reads and modifies the some_var logical atomic operation.

Example 3

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

Time.sleep () can cause a thread to hang and force a thread switch to occur.

From threading Import Threadimport Timeclass Createlistthread (Thread):    def run (self):        self.entries = []        For I in range:            time.sleep (1)            self.entries.append (i)        print self.entriesdef Use_create_list_ Thread (): For    I in range (3):        t = createlistthread ()        T.start () Use_create_list_thread ()

Run a few times and find that the results are not printed out. When a line is impersonating in print, the CPU switches to another thread, resulting in incorrect results. We need to make sure that print self.entries it's a logical atomic operation to avoid being interrupted by other threads while printing.

We used lock () to see the example below.

From threading import Thread, Lockimport timelock = Lock () class Createlistthread (Thread):    def run (self):        Self.entries = [] for        i in range:            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 right results. proves that a thread can not modify variables (non-global variables) inside other threads.

Original source: Akshar Raaj

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.