0

I want to run 2 functions at the same time. Then wait until those 2 functions are over, and it can start processing the rest of codes. I tried to use thread module but it just continue running without waiting those 2 functions finished. My example codes are as below:

import os, sys
import threading
from threading import Thread

class Example():
    def __init__(self):
        self.method_1()

    def method_1(self):
        for i in range(3):
            print ('new')

            def run(self):
                threading.Thread(target = function_a, args=(self,)).start()
                threading.Thread(target = function_b, args=(self,)).start()

            def function_a(self):
                for i in range(10):
                    print (1)

            def function_b(self):
                for i in range(10):
                    print (2)

            run(self)


Example()

If the above codes get executed, the print ("new") inside method_1 will just print out immediately even before the function_a and function_b are over in each round of the for i in range(3). However, what I want is that the new will only be printed out as function_a and function_b are finished printing 1 and 2.

That is, the codes should stop at threading and wait for the function_a and function_b to finish so that it can continue processing the next i in the for i in range(3).

If anyone know how to solve this, please let me know. Appreciated!!

Josh Karpel
  • 2,110
  • 2
  • 10
  • 21
ryan9025
  • 267
  • 6
  • 17
  • I am no expert in threading, why not use multiprocessing module if you want to run two functions in parallel. That'd be a more solid approach – Satish Oct 19 '17 at 14:17
  • I am no expert in `threading` nor `multiprocessing` too... Could you pls provide an example or solution using `multiprocessing` if possible? Appreciated!! – ryan9025 Oct 19 '17 at 14:20
  • See if this will help https://www.youtube.com/watch?v=aysceqdGFw8&t=482s – Satish Oct 19 '17 at 14:22
  • https://stackoverflow.com/questions/3044580/multiprocessing-vs-threading-python?rq=1 – Satish Oct 19 '17 at 14:24
  • I don't know if your videos is suitable for this questions.. Because for my question there is a `for loop` before the `threading`. But there's no `for loop` in that video. I just want the `threading` stops before the functions are finished so it can start processing the next round of the `for loop`. – ryan9025 Oct 19 '17 at 14:44

2 Answers2

1

As already pointed out in the other answer, you need to join the threads. This example keeps your structure. I have added a sleep there so that you can see it works (otherwise buffered output might mess things up).

import os, sys
import threading
from threading import Thread
from time import sleep

class Example():
    def __init__(self):
        self.method_1()

    def method_1(self):
        for i in range(3):
            print ('new')

            def run(self):
                a=threading.Thread(target = function_a, args=(self,))
                b=threading.Thread(target = function_b, args=(self,))
                a.start()
                b.start()
                a.join()
                b.join()

            def function_a(self):
                for i in range(10):
                    print (1)

            def function_b(self):
                for i in range(10):
                    print (2)

            run(self)
            sleep(1)


Example()
Hannu
  • 11,685
  • 4
  • 35
  • 51
  • Appreciated!! Sorry that I have to give the answer to the other one becos he answers first. But this solution is perfect as well – ryan9025 Oct 19 '17 at 15:10
0

You need to join the threads (join means "wait for it to finish"). See the docs. Depending on your problem, you may want to use multiprocessing instead, as mentioned in the comments. I'll proceed under the assumption that you do want to do threading.

Defining a class with methods to ask your question was unnecessary (and, even worse, you're redefining run, function_a, and function_b on every iteration). Just use some functions. You can turn them into methods later if you need to.

import time
import threading

def function_a():
    for i in range(5):
        print('a', i)
        time.sleep(.1)

def function_b():
    for i in range(5):
        print('b', i)
        time.sleep(.1)

def run():
    thread_a = threading.Thread(target = function_a)
    thread_b = threading.Thread(target = function_b)

    thread_a.start()
    thread_b.start()

    print('threads started')

    return thread_a, thread_b

for i in range(3):
    print('new', i)

    thread_a, thread_b = run()

    print('about to join threads')

    thread_a.join()
    thread_b.join()

    print('threads joined')

The sleeps are just there to show that the two threads really are running at the same time. Example output (which may vary from run to run depending on exact timing):

new 0
a 0
b 0
threads started
about to join threads
a 1
b 1
a 2
b 2
a 3
b 3
a 4
b 4
threads joined
new 1
a 0
b 0
threads started
about to join threads
a 1
b 1
a 2
b 2
a 3
b 3
a 4
b 4
threads joined
new 2
a 0
b 0
threads started
about to join threads
a 1
b 1
b 2
a 2
b 3
a 3
b 4
a 4
threads joined

EDIT: class-based example

class Example():
    def function_a(self):
        for i in range(5):
            print('a', i)
            time.sleep(.1)

    def function_b(self):
        for i in range(5):
            print('b', i)
            time.sleep(.1)

    def get_threads(self):
        thread_a = threading.Thread(target = self.function_a)
        thread_b = threading.Thread(target = self.function_b)

        thread_a.start()
        thread_b.start()

        print('threads started')

        return thread_a, thread_b

    def run(self):
        for i in range(3):
            print('new', i)

            thread_a, thread_b = self.get_threads()

            print('about to join threads')

            thread_a.join()
            thread_b.join()

            print('threads joined')

e = Example()
e.run()
Josh Karpel
  • 2,110
  • 2
  • 10
  • 21
  • Umm actually all these class/method/function has to remain the exact same structures... Because I'm building a much larger program and it's just a very small part of codes in this example. – ryan9025 Oct 19 '17 at 14:40
  • No worries - it should be easy to adapt my example to make the structure more like yours. Just move the functions you define in the loop into the class definition, and `join` the threads before you go to the next iteration of the loop. – Josh Karpel Oct 19 '17 at 14:42
  • Could you pls provide an solution with a class like mine? I tried but it didn't work... It's just very confusing with those `self` arguments involved. – ryan9025 Oct 19 '17 at 14:48
  • @ryan9025 Done. – Josh Karpel Oct 19 '17 at 14:51
  • Umm...thanks but I need the `run`, `funciton_a` and `function_b` inside the `method_1`. I'm still trying to revise your codes but could you pls provide an solution just in the exact same structure of my codes? Cos I put this example in this structure for a reason... Really appreciated!! – ryan9025 Oct 19 '17 at 14:52
  • 1
    @ryan9025 You really don't. I'm having trouble imagining a situation where you couldn't define them on the class itself and just pass in whatever information they need from inside `run`. You almost certainly don't need to redefine them on every loop like you do in your code. – Josh Karpel Oct 19 '17 at 14:55
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/157072/discussion-between-josh-karpel-and-ryan9025). – Josh Karpel Oct 19 '17 at 14:55