在进行数据处理时,为了减少时间等待,不可避免的会遇到多线程和多进程的使用.

这里以图片的可用性检测为例,实现多线程.

1. 进程和线程的概念

From:进程线程面试题总结

[1] - 进程是表示资源分配的基本单位,又是调度运行的基本单位.

例如,用户运行自己的程序,系统就创建一个进程,并为它分配资源,包括各种表格、内存空间、磁盘空间、I/O设备等. 然后,把该进程放人进程的就绪队列. 进程调度程序选中它,为它分配CPU以及其它有关资源,该进程才真正运行. 所以,进程是系统中的并发执行的单位.

[2] - 线程是进程中执行运算的最小单位,亦即执行处理机调度的基本单位.

如果把进程理解为在逻辑上操作系统所完成的任务,那么线程表示完成该任务的许多可能的子任务之一.

例如,假设用户启动了一个窗口中的数据库应用程序,操作系统就将对数据库的调用表示为一个进程. 假设用户要从数据库中产生一份工资单报表,并传到一个文件中,这是一个子任务;在产生工资单报表的过程中,用户又可以输人数据库查询请求,这又是一个子任务. 这样,操作系统则把每一个请求――工资单报表和新输人的数据查询表示为数据库进程中的独立的线程. 线程可以在处理器上独立调度执行,这样,在多处理器环境下就允许几个线程各自在单独处理器上进行. 操作系统提供线程就是为了方便而有效地实现这种并发性.

举个例子来说,多线程就像是火车上的每节车厢,而进程就是火车.

1.1 多进程和多线程的区别

如图:

2. Python 多线程例示 - 图片可用性检测

深度学习中,图像在使用前,有必要提前检测图片的可用性和完整性.

图片可用性检测 - Premature end of JPEG file - AIUAI

对于大规模图像数据集,采用多线程可以明显减少图片检测时间.

#~--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
Last modification:December 11th, 2018 at 05:28 pm