Python 进程,线程,多进程,多线程,线程池的使用方式

需求场景:

由于业务需求,需要将保存在OSS上的图片数据,以用户的角度去拉取,为了减少代码量所以放弃了java采取了python,由于数据总量在200w张照片,所以需要多线程去拉取节省时间。

一、进程与线程的联系和区别

线程是该进程的一条执行路径,是程序执行时的最小单位,它是进程的一个执行流,负责CPU调度和分派,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理

二、python中的进程与多进程

多进程如果将进程池数量开启过多,容易导致电脑死机,所以采取多线程的方式


import time
import socket
import urllib.request as request
import threading
from logging import getLogger, INFO
from concurrent_log_handler import ConcurrentRotatingFileHandler
import os

import multiprocessing

# 请求oss下载超时时间
socket.setdefaulttimeout(120)

# 记录日志
log = getLogger()
logfile = os.path.abspath("wo.log")
rotateHandler = ConcurrentRotatingFileHandler(logfile, "a", 512 * 1024, 5)
log.addHandler(rotateHandler)
log.setLevel(INFO)


# 将远程数据下载到本地,第二个参数就是要保存到本地的文件名

def test(xx, y, q):  # Use thread.start_new_thread() to create 2 new threads
    pass  # 下载数据

if __name__ == '__main__':
    # 开启一个新进程 multiprocessing.process(方法,args=(方法参数,))
    # multiprocessing.process(test,args=(xx,y,q,)
    multiprocessing.freeze_support()
    # 开启进程池
    p = multiprocessing.Pool(10)
    for i in range(1, 11):
        if i == 1:
            star = 0
        else:
            star = (i - 1) * 35000
        p.apply_async(test, args=(result, star, i * 35000,))  # 异步方式去开启进程
    p.close()
    p.join()
    print("所有进程执行完毕")

三、python中的线程与多线程

# -*- coding: UTF-8 -*-
import threading
from time import ctime
import csv  # 系统内置模块
import socket
import urllib.request as request
from logging import getLogger, INFO
from concurrent_log_handler import ConcurrentRotatingFileHandler
import os

socket.setdefaulttimeout(120)

log = getLogger()
# Use an absolute path to prevent file rotation trouble.
logfile = os.path.abspath("test.log")
# Rotate log after reaching 512K, keep 5 old copies.
rotateHandler = ConcurrentRotatingFileHandler(logfile, "a", 512 * 1024, 5)
log.addHandler(rotateHandler)
log.setLevel(INFO)





class myThread(threading.Thread):
    def __init__(self, threadID, name, s, e):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name
        self.s = s
        self.e = e

    def run(self):
        print("Starting " + self.name + ctime())
        # 获得锁,成功获得锁定后返回True
        # 可选的timeout参数不填时将一直阻塞直到获得锁定
        # 否则超时后将返回False
        # 线程需要执行的方法
        threadLock.acquire()
        # 线程需要执行的方法
        printImg(self.s, self.e)
        # 释放锁
        threadLock.release()
        

# 按照分配的区间,读取列表内容,需要其他功能在这个方法里设置
def printImg(s, e):
    pass


totalThread = 21  # 需要创建的线程数,可以控制线程的数量
#
threadLock = threading.Lock()  # 锁
threads = []  # 创建线程列表
# 创建新线程和添加线程到列表
for i in range(1, 21):
    thread = 'thread%s' % i
    if i == 1:
        star = 0
    else:
        star = (i - 1) * 18000

    thread = myThread(i, "Thread-%s" % i, star, i * 18000)
    threads.append(thread)  # 添加线程到列表
    thread.start() # 开启线程

# 等待所有线程完成
for t in threads:
    # 依次检验线程池中的线程是否结束,没有结束就阻塞直到线程结束,如果结束则跳转执行下一个线程的join函数。
    t.join() 
print("Exiting Main Thread")

四、python中的线程池或进程池(推荐使用这个)

前面两个写法都有点太不优雅,无法更好的管理多线/进进程。所以引入了线/进程池的概念,可以理解为开一家租车店(线/进程池),一共有20辆车(20个线/进程),有人来租车的时候,找一个没有被租赁的车给他,使用完放回车库,等下一个有需求的人进来在分配,这样可以更好的管理多线/进程。

import csv  # 系统内置模块
import socket
import urllib.request as request
from logging import getLogger, INFO
from concurrent_log_handler import ConcurrentRotatingFileHandler
import os
from concurrent.futures import ThreadPoolExecutor

socket.setdefaulttimeout(120)

log = getLogger()
# Use an absolute path to prevent file rotation trouble.
logfile = os.path.abspath("zz.log")
# Rotate log after reaching 512K, keep 5 old copies.
rotateHandler = ConcurrentRotatingFileHandler(logfile, "a", 512 * 1024, 5)
log.addHandler(rotateHandler)
log.setLevel(INFO)



def mkdir(path):
    # 去除首位空格
    path = path.strip()
    # 去除尾部 \ 符号
    path = path.rstrip("\\")
    # 判断路径是否存在
    # 存在     True
    # 不存在   False
    isExists = os.path.exists(path)
    # 判断结果
    if not isExists:
        # 如果不存在则创建目录
        # 创建目录操作函数
        os.makedirs(path)
        # print (path + ' 创建成功')
        return True
    else:
        return False


# 将远程数据下载到本地,第二个参数就是要保存到本地的文件名
#
# urllib.request.urlretrieve('链接',
#                    'D:/1.jpg')
# csv文件读写 csv每一行用,分割 换行则是切行

with open('q2w.csv') as fileRead:
    f_csv = csv.reader(fileRead)
    result = list(f_csv)


def test(y, q): 
    print(str(y) + '-' + str(q - 1))
    for count in range(y, q):
        row = result[count]
        ss = 'E:/test/' + row[2]
        mkdir(ss)
        reul = ''
        try:
            if not os.path.exists(ss + '/01_' + row[3] + '.png'):
                request.urlretrieve(row[0],
                                    ss + '/01_' + row[3] + '.png')
                reul += ','
        except Exception as e:
            print("m")
            reul += str(row[0]) + ","
            print(e)
        try:
            if not os.path.exists(ss + '/02_' + row[3] + '.png'):
                if row[1] is not None and row[1] != '':
                    request.urlretrieve(row[1],
                                        ss + '/02_' + row[3] + '.png')
                reul += ','
        except Exception as e:
            print("f" + str(row[1]))
            reul += str(row[1]) + ','
            print(e)


if __name__ == '__main__':
	# 开启线程池 ThreadPoolExecutor(max_workers(线程的最多数量),thread_name_prefix(线程池内线程的名称前缀)) 
    threadPool = ThreadPoolExecutor(max_workers=40, thread_name_prefix="test_")
    # 开启进程池 ProcessPoolExecutor(max_workers(进程的最多数量),thread_name_prefix(进程池内线程的名称前缀))
    for i in range(1, 37):
        if i == 1:
            star = 0
        else:
            star = (i - 1) * 10000
        # submit('当前线程需要执行的具体逻辑',参数1,参数2)
        future = threadPool.submit(test, star, i * 10000)  
       
    print("所有进程执行完毕")

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值