There are three ways to implement python multi-tasking. They are multi-processing, multi-threading and coroutine. Multi-processing is the most cumbersome way among these three and coroutine is the lightest.
Table of Contents
Multi-threading
Use threading.Thread method to create threads
python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import threading
deftest1(n):for i in range(n):
print("----test1---%d---"%i)
deftest2(n):for i in range(n):
print("----test2---%d---"%i)
defmain():
t1 = threading.Thread(target=test1, args=(5,))
t2 = threading.Thread(target=test2, args=(5,))
t1.start()
t2.start()
if __name__ == "__main__":
main()
Create thread by using a class to inherit from threading.Thread
python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
import threading
import time
classMyThread(threading.Thread):def__init__(self,n):
super().__init__()
self.n = n
defrun(self):
for i in range(self.n):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i)
print(msg)
if __name__ == "__main__":
t = MyThread(5)
t.start()
Multi-processing
The usage of multiprocessing module is very similar to the multithreading module.
python
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
import multiprocessing
deftest1(n):for i in range(n):
print("----test1---%d---"%i)
deftest2(n):for i in range(n):
print("----test2---%d---"%i)
defmain():
p1 = multiprocessing.Process(target=test1, args=(5,))
p2 = multiprocessing.Process(target=test2, args=(5,))
p1.start()
p2.start()
if __name__ == "__main__":
main()
Coroutine
Coroutine originated from generator. There is always one thread that is running. Coroutine makes one thread switch between different functions so that it looks like multi-tasking.
Here is an example that a generator can switch from one function to another
Generator can make two functions switch from one to another. However it is too complicated to write like this. In python, we have two packages, greenlet and gevent to implement coroutine. No need to write any yield statement in your function and then manage them in the main thread.
from greenlet import greenlet
import time
deftest1():whileTrue:
print("---A---")
gr2.switch()
time.sleep(0.5)
deftest2():whileTrue:
print("---B---")
gr1.switch()
time.sleep(0.5)
gr1 = greenlet(test1)
gr2 = greenlet(test2)
#switch to gr1 to run
gr1.switch()
gevent is a wrapper around greenlet. When you use greenlet, you still need to manually switch by explicit calling greenlet.switch() method.
Comparatively, gevent will switch whenever it encountered a blocking function, such as time.sleep() and various of socket functions. But the sleep function must use the one in gevent package.
Luckily we have monkey.patch_all() that will change the blocking functions in other packages to the blocking functions in gevent package. Here is an example:
import gevent
import time
from gevent import monkey
#use this to avoid manual change "time.sleep(0.5)" to "gevent.sleep(0.5)"
monkey.patch_all()
deff1(n):for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
deff2(n):for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
deff3(n):for i in range(n):
print(gevent.getcurrent(),i)
time.sleep(0.5)
print("-----1-----")
g1 = gevent.spawn(f1,5)
print("-----2-----")
g2 = gevent.spawn(f2,5)
print("-----3-----")
g3 = gevent.spawn(f3,5)
print("-----4-----")
g1.join()
g2.join()
g3.join()