在进行数据处理时,为了减少时间等待,不可避免的会遇到多线程和多进程的使用.
这里以图片的可用性检测为例,实现多线程.
1. 进程和线程的概念
From:进程线程面试题总结
[1] - 进程是表示资源分配的基本单位,又是调度运行的基本单位.
例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等. 然后,把该进程放人进程的就绪队列. 进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行. 所以,进程是系统中的并发执行的单位.
[2] - 线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位.
如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一.
例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程. 假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务. 这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程. 线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行. 操作系统提供线程就是为了方便而有效地实现这种并发性.
举个例子来说,多线程就像是火车上的每节车厢,而进程就是火车.
1.1 多进程和多线程的区别
如图:
2. Python 多线程例示 - 图片可用性检测
深度学习中,图像在使用前,有必要提前检测图片的可用性和完整性.
对于大规模图像数据集,采用多线程可以明显减少图片检测时间.
#~--coding:utf-8 --*--
import os
import json
import numpy as np
from PIL import Image
import threading,signal
import time
import socket
socket.setdefaulttimeout(10.0)
def check_image(start, end, images_list):
global record,count,count_invalid,is_exit
im_names = []
for img_name in images_list[start:end]:
try:
img = Image.open(img_name)
# 避免出现 RGBAlpha 四通道的图像
if len(img.split()) == 3:
# print(img.size)
valid_file.write(img_name + '\n')
except:
print('Error Image ...', img_name)
invalid_file.write(img_name + '\n')
count_invalid += 1
if __name__ == "__main__":
num_threads = 16 # 线程数
images_list = open('images_list.txt').readlines()
count = len(images_list)
print('[INFO] Num of Images: ', count)
count_invalid = 0
record = 0
part = int(count/num_threads)
with open('images_valid.txt', 'w') as valid_file,
open('images_invalid.txt','w') as invalid_file:
thread_list = []
for i in range(num_threads):
if(i == num_threads-1):
t = threading.Thread(target = check_image,
kwargs={'start':i*part,
'end':count,
'images_list': images_list})
else:
t = threading.Thread(target=check_image,
kwargs={'start': i * part,
'end': (i + 1) * part,
'images_list': images_list})
t.setDaemon(True)
# Thread.setDaemon(true)设置为守护线程
# Thread.setDaemon(false)设置为用户线程
thread_list.append(t)
t.start()
for i in range(num_threads):
try:
while thread_list[i].isAlive():
pass
except KeyboardInterrupt:
break
if count_invalid == 0:
print ("all {} images have been checked!".format(count))
else:
print("{}/{} images have been checked, {} images are invalid".
format(count - count_invalid, count, count_invalid))
print('[INFO] Done.')
2.1 Ubuntu 查看运行的线程
两种方式:
[1] - cat 命令 - cat /proc/<pid>/status
:
首先,终端运行 top
命令,查看对应进程的 <pid>
;
然后,终端运行 cat /proc/<pid>/status
命令,查看进程状态,输出如下:
Name: python
Umask: 0002
State: R (running)
Tgid: 26976
Ngid: 0
Pid: 26976
PPid: 20213
TracerPid: 0
Uid: 1001 1001 1001 1001
Gid: 1001 1001 1001 1001
FDSize: 256
Groups: 4 27 1001
NStgid: 26976
NSpid: 26976
NSpgid: 26976
NSsid: 20213
VmPeak: 1879060 kB
VmSize: 1879060 kB
VmLck: 0 kB
VmPin: 0 kB
VmHWM: 949684 kB
VmRSS: 533400 kB
RssAnon: 529936 kB
RssFile: 3464 kB
RssShmem: 0 kB
VmData: 789392 kB
VmStk: 132 kB
VmExe: 2936 kB
VmLib: 51080 kB
VmPTE: 1416 kB
VmSwap: 0 kB
HugetlbPages: 0 kB
CoreDumping: 0
Threads: 20 # 线程数
SigQ: 0/128185
SigPnd: 0000000000000000
ShdPnd: 0000000000000000
SigBlk: 0000000000000000
SigIgn: 0000000001001000
SigCgt: 0000000180000002
CapInh: 0000000000000000
CapPrm: 0000000000000000
CapEff: 0000000000000000
CapBnd: 0000003fffffffff
CapAmb: 0000000000000000
NoNewPrivs: 0
Seccomp: 0
Speculation_Store_Bypass: thread vulnerable
Cpus_allowed: f
Cpus_allowed_list: 0-3
Mems_allowed: 00000000,00000000,
Mems_allowed_list: 0
voluntary_ctxt_switches: 12567154
nonvoluntary_ctxt_switches: 2385502
[2] - top 命令 - top -H -p <pid>
终端运行 top -H -p <pid>
命令,输出如下:
top - 17:23:32 up 7 days, 2:43, 1 user, load average: 18.72, 18.66, 18.75
Threads: 20 total, 3 running, 17 sleeping, 0 stopped, 0 zombie
%Cpu(s): 9.8 us, 2.1 sy, 0.0 ni, 85.7 id, 2.3 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem : 32882184 total, 259352 free, 20003040 used, 12619792 buff/cache
KiB Swap: 33492988 total, 32561148 free, 931840 used. 12079924 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
26976 hgf 20 0 1879060 533380 3444 R 81.2 1.6 273:20.52 python
27021 hgf 20 0 1879060 533380 3444 D 18.8 1.6 19:16.64 python
27010 hgf 20 0 1879060 533380 3444 D 12.5 1.6 19:47.36 python
27014 hgf 20 0 1879060 533380 3444 D 12.5 1.6 19:31.60 python
27016 hgf 20 0 1879060 533380 3444 R 12.5 1.6 19:25.91 python
27017 hgf 20 0 1879060 533380 3444 D 12.5 1.6 19:17.79 python
27023 hgf 20 0 1879060 533380 3444 D 12.5 1.6 19:24.55 python
27019 hgf 20 0 1879060 533380 3444 D 6.2 1.6 19:29.53 python
26977 hgf 20 0 1879060 533380 3444 S 0.0 1.6 0:00.07 python
26978 hgf 20 0 1879060 533380 3444 S 0.0 1.6 0:00.07 python
26979 hgf 20 0 1879060 533380 3444 S 0.0 1.6 0:00.06 python
27011 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:27.57 python
27012 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:35.67 python
27013 hgf 20 0 1879060 533380 3444 D 0.0 1.6 24:12.61 python
27015 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:24.18 python
27018 hgf 20 0 1879060 533380 3444 R 0.0 1.6 19:25.23 python
27020 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:29.50 python
27022 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:29.33 python
27024 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:26.84 python
27025 hgf 20 0 1879060 533380 3444 D 0.0 1.6 19:25.59 python