多线程和多进程 - 初窥
一、说明
在平常工作中,我们使用top命令查看一台linux服务器的cpu使用情况时,会发现某个进程的cpu使用率会超过100%,这是为什么?
二、举例
实验环境为 CentOS7.6 + Python2.7
1. 多线程、多进程在操作系统中的表现形式
我们首先看两个例子,test1.py和test2.py,都是执行死循环,test1.py两个线程,test2.py两个进程。
【test1.py】 -- 多线程
import threading
def foo():
while 1:
pass
task1 = threading.Thread(target=foo)
task2 = threading.Thread(target=foo)
task1.start()
task2.start()
执行:python test1.py,然后开启另一个窗口,执行top查看cpu使用情况(如果是多核处理器,按“1”可以看每一个cpu核的使用情况)。
【test2.py】 -- 多进程
import multiprocessing
def foo():
while 1:
pass
task1 = multiprocessing.Process(target=foo)
task2 = multiprocessing.Process(target=foo)
task1.start()
task2.start()
杀掉test1的进程,执行:python test2.py,然后开启另一个窗口,执行top查看cpu使用情况。
通过上面两个例子可以看到,test1只有一个进程,单个进程的cpu使用率超过100%,且该进程在两个cpu核上执行。test2有两个进程,每个进程的cpu使用率为100%,也在两个cpu核上执行。
2. 单线程、多线程、多进程的运行速度
接下来我们再来看三个例子,test3.py、test4.py和test5.py,都是将值做一亿次减法。test3.py采用单线程,test4.py采用多线程,test5.py采用多进程。
【test3.py】 -- 单线程
import time
N = 100000000
def foo(n):
while n > 0:
n -= 1
start = time.time()
foo(N)
end = time.time()
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test3.py
Time taken in seconds: 2.91
【test4.py】 -- 多线程
import time
import threading
N = 100000000
def foo(n):
while n > 0:
n -= 1
task1 = threading.Thread(target=foo, args=(N/2,))
task2 = threading.Thread(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test4.py
Time taken in seconds: 6.0
【test5.py】 -- 多进程
import time
import multiprocessing
N = 100000000
def foo(n):
while n > 0:
n -= 1
task1 = multiprocessing.Process(target=foo, args=(N/2,))
task2 = multiprocessing.Process(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test5.py
Time taken in seconds: 1.48
可以看到多线程比单线程的效率低一倍,多进程比单线程的效率高一倍。我使用多线程的目的无非是想让程序快一点,反而慢了。
3. 单线程、多线程、多进程的执行结果
接下来我们再来看三个例子,test6.py、test7.py和test8.py,都是将值做一千万次加法,最后打印这个值。test6.py采用单线程,test7.py采用多线程,test8.py采用多进程。
【test6.py】 -- 单线程
import time
N = 10000000
sum = 0
def foo(n):
global sum
for i in range(0, n):
sum += 1
start = time.time()
foo(N)
end = time.time()
print('The value of sum: {}'.format(sum))
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test6.py
The value of sum: 10000000
Time taken in seconds: 1.26
【test7.py】 -- 多线程
import time
import threading
N = 10000000
sum = 0
def foo(n):
global sum
for i in range(0, n):
sum += 1
task1 = threading.Thread(target=foo, args=(N/2,))
task2 = threading.Thread(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('The value of sum: {}'.format(sum))
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test7.py
The value of sum: 7333348
Time taken in seconds: 1.76
【test8.py】 -- 多进程
import time
import multiprocessing
N = 10000000
sum = 0
def foo(n):
global sum
for i in range(0, n):
sum += 1
task1 = multiprocessing.Process(target=foo, args=(N/2,))
task2 = multiprocessing.Process(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('The value of sum: {}'.format(sum))
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test8.py
The value of sum: 0
Time taken in seconds: 0.57
可以看到上面三种不同的写法,得出来的结果都不一样。
我将test7.py和test8.py都改造一下,分别为test9.py和test10.py
【test9.py】 -- 多线程
import time
import threading
N = 10000000
sum = 0
lock = threading.Lock()
def foo(n):
global sum
global lock
for i in range(0, n):
with lock:
sum += 1
task1 = threading.Thread(target=foo, args=(N/2,))
task2 = threading.Thread(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('The value of sum: {}'.format(sum))
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test9.py
The value of sum: 10000000
Time taken in seconds: 21.49
【test10.py】 -- 多进程
import time
import multiprocessing
N = 10000000
sum = multiprocessing.Value('i', 0)
lock = multiprocessing.Lock()
def foo(n):
global sum
global lock
for i in range(0, n):
with lock:
sum.value += 1
task1 = multiprocessing.Process(target=foo, args=(N/2,))
task2 = multiprocessing.Process(target=foo, args=(N/2,))
start = time.time()
task1.start()
task2.start()
task1.join()
task2.join()
end = time.time()
print('The value of sum: {}'.format(sum.value))
print('Time taken in seconds: {}'.format(round(end-start, 2)))
[root@34host ~]# python test10.py
The value of sum: 10000000
Time taken in seconds: 41.3
可以看到结果都是正确的了,但是执行的时间却比之前长了很多,而且多进程还要慢于多线程。
三、问题
上面的例子,就在我大脑中产生了很多的疑惑。我后面将依次解开这些谜底。
- 多线程跟多进程有什么区别,什么时候用多线程,什么时候用多进程?
- 单线程、多线程、多进程的效率问题?
- 多线程、多进程在编程的时候有哪些注意事项?