小豹子的网络记事本

记录每一个有意思的细节

多线程和多进程 - 初窥

一、说明

在平常工作中,我们使用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核的使用情况)。
1.png

【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使用情况。
2.png

通过上面两个例子可以看到,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

可以看到结果都是正确的了,但是执行的时间却比之前长了很多,而且多进程还要慢于多线程。

三、问题

上面的例子,就在我大脑中产生了很多的疑惑。我后面将依次解开这些谜底。

  1. 多线程跟多进程有什么区别,什么时候用多线程,什么时候用多进程?
  2. 单线程、多线程、多进程的效率问题?
  3. 多线程、多进程在编程的时候有哪些注意事项?
posted @ 2024-05-20 08:59  小豹子加油  阅读(24)  评论(0编辑  收藏  举报