这是一个可停止线程的有限容量有限并行度的任务管理器

基于:GitHub - AlitaIcon/StopableThreadJob: 可停止线程任务管理器

Quick Start

基础调用与效果

import time
import datetime
from loguru import logger from StopableThreadJob.job_manager import JobManager if __name__ == '__main__':
def slow_func( name):
for i in range(5):
logger.info(f"{name} -- {datetime.datetime.now()}")
time.sleep(1) job_manager = JobManager()
# 删除未添加任务
job_manager.remove_job('2')
for pid in range(6):
logger.info(f"添加任务: {pid}")
job_manager.add_job(target=slow_func, args=(pid,), job_id=f'{pid}')
time.sleep(1)
job_manager.start_job()
# 删除已添加运行中任务
job_manager.remove_job('1')
# 删除已添加未运行中任务
job_manager.remove_job('4')
time.sleep(5)
# 删除运行完成任务
job_manager.remove_job('0')
job_manager.print_current_job()
print(job_manager.job_store)
for i in [0, 1, 2, 4]:
logger.info(f"添加任务: {i}")
job_manager.add_job(target=slow_func, args=(i,), job_id=f'{i}')
job_manager.print_current_job()
job_manager.start_job()
time.sleep(6)
print(job_manager.job_store)
job_manager.print_current_job()
time.sleep(30)

文件job_manager

import ctypes
import threading
from loguru import logger class TerminableThread(threading.Thread):
"""
a thread that can be stopped by forcing an exception in the execution context
可以通过在执行上下文中强制异常来停止的线程
""" def terminate(self, exception_cls, repeat_sec=2.0):
if self.is_alive() is False:
return True
killer = ThreadKiller(self, exception_cls, repeat_sec=repeat_sec)
killer.start() class ThreadKiller(threading.Thread):
"""
separate thread to kill TerminableThread
单独的线程来终止可终止线程
""" def __init__(self, target_thread, exception_cls, repeat_sec=2.0):
threading.Thread.__init__(self)
self.target_thread = target_thread
self.exception_cls = exception_cls
self.repeat_sec = repeat_sec
self.daemon = True def run(self):
"""loop raising exception incase it's caught hopefully this breaks us far out"""
while self.target_thread.is_alive():
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(self.target_thread.ident),
ctypes.py_object(self.exception_cls))
self.target_thread.join(self.repeat_sec) # 自定义错误类型:
class StopRunningCommand(Exception):
pass class JobManagerID:
"""
任务ID池,用于初始化任务ID列表,
"""
def __init__(self, pool_size=5):
self.pid_list = list(range(pool_size)) def list_move(self):
# 将pid_list 列表循环左移一位,既列表第一项移动至末尾
b = self.pid_list[:1][0]
c = self.pid_list[1:]
c.append(b)
self.pid_list = c # 主要的任务调用对象类
class JobManager: def __init__(self, semaphore=2):
"""
:param semaphore: 任务池中可并行的任务数
"""
self.job_store = {}
self.job_lock = threading.RLock()
self.semaphore = threading.Semaphore(semaphore) def add_job(self, job_id, target, *args, **kwargs):
# 新增指定ID的任务
def inner_job(*args, **kwargs):
try:
self.semaphore.acquire()
ret = target(*args, **kwargs)
print(f"{job_id} is finished.")
return ret
except StopRunningCommand as e:
print(f"{job_id} has been stopped.")
except Exception as e:
print(f"{job_id} is finished.")
raise e
finally:
if job_id in self.job_store:
self.job_store.pop(job_id) # 运行完毕后在job_store中删除任务
self.semaphore.release() with self.job_lock:
t = TerminableThread(target=inner_job, *args, **kwargs)
t.daemon = True
# if job_id in self.job:
# self.job[job_id].terminate(StopRunningCommand)
self.job_store[job_id] = t
return self.job_store[job_id] def remove_job(self, job_id):
# 删除指定ID的任务
with self.job_lock:
if job_id in self.job_store:
self.job_store[job_id].terminate(StopRunningCommand) def start_job(self):
# 开始任务池中全部的任务,当任务执行较快时会出现该循环还未结束但已经有任务结束了,
# 从而导致循环的字典发生变化导致错误
with self.job_lock:
for j, t in self.job_store.items():
if t.is_alive() is False:
t.start()
def start_job_id(self,pid):
# 指定id开始执行任务
with self.job_lock:
if self.job_store[pid].is_alive() is False:
self.job_store[pid].start() def job_start(self,pid):
# 返回指定id的任务当前状态,True为正在计算
return self.job_store[pid].is_alive() def print_current_job(self):
# 返回指定任务池中全部的任务的当前状态,True为正在计算
info = {jid: t.is_alive() for jid, t in self.job_store.items()}
logger.info(info)

为实现任务运行异步且可并行的效果

定义的方法函数

from StopableThreadJob.job_manager import *
job_manager = JobManager(semaphore=4)
job_manager_list = JobManagerID(pool_size = 5)
# pool_size 用于设置任务池容量的大小
# semaphore 用于设置并行度,既任务池中可同时计算的任务数 def job():
def slow_func(name):
for i in range(10):
logger.info(f"{name} -- {datetime.datetime.now()}")
time.sleep(1) pid = job_manager_list.pid_list[0]
if pid in job_manager.job_store:
job_manager.remove_job(pid)
job_manager.add_job(target=slow_func, args=(pid,), job_id=pid)
job_manager.start_job_id(pid)
job_manager_list.list_move()
  • pool_size 用于设置任务池容量的大小
  • semaphore 用于设置并行度,既任务池中可同时计算的任务数

实现有限的任务池以及有限的并行度的计算模块。

当任务池满的时候新的任务会将旧的任务挤出任务池。

所有的任务都在任务池中排队,根据并行度决定同时计算的数目。

这是一个基于threading可停止线程的有限容量有限并行度的python任务管理器的更多相关文章

  1. Java模拟生产者-消费者问题。生产者不断的往仓库中存放产品,消费者从仓库中消费产品。其中生产者和消费者都可以有若干个。在这里,生产者是一个线程,消费者是一个线程。仓库容量有限,只有库满时生产者不能存

    需求分析:生产者生产产品,存放在仓库里,消费者从仓库里消费产品. 程序分析: 1.生产者仅仅在仓储未满时候生产,仓满则停止生产. 2.消费者仅仅在仓储有产品时候才能消费,仓空则等待. 3.当消费者发现 ...

  2. Java 创建线程/停止线程

    继承 Thread 类 class MyThread1 extends Thread{ @Override public void run(){ System.out.println("继承 ...

  3. 如何停止一个正在运行的java线程

    与此问题相关的内容主要涉及三部分:已废弃的Thread.stop().迷惑的thread.interrupt系列.最佳实践Shared Variable. 已废弃的Thread.stop() @Dep ...

  4. 一个基于.NET平台的自动化/压力测试系统设计简述

    AutoTest系统设计概述 AutoTest是一个基于.NET平台实现的自动化/压力测试的系统,可独立运行于windows平台下,支持分布式部署,不需要其他配置或编译器的支持.(本质是一个基于协议的 ...

  5. 基于condition 实现的线程安全的优先队列(python实现)

    可以把Condiftion理解为一把高级的琐,它提供了比Lock, RLock更高级的功能,允许我们能够控制复杂的线程同步问题.threadiong.Condition在内部维护一个琐对象(默认是RL ...

  6. 基于C++11实现线程池的工作原理

    目录 基于C++11实现线程池的工作原理. 简介 线程池的组成 1.线程池管理器 2.工作线程 3.任务接口, 4.任务队列 线程池工作的四种情况. 1.主程序当前没有任务要执行,线程池中的任务队列为 ...

  7. Go/Python/Erlang编程语言对比分析及示例 基于RabbitMQ.Client组件实现RabbitMQ可复用的 ConnectionPool(连接池) 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil 分享基于MemoryCache(内存缓存)的缓存工具类,C# B/S 、C/S项目均可以使用!

    Go/Python/Erlang编程语言对比分析及示例   本文主要是介绍Go,从语言对比分析的角度切入.之所以选择与Python.Erlang对比,是因为做为高级语言,它们语言特性上有较大的相似性, ...

  8. 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发

    ''' 写一个基于TCP协议套接字,服务端实现接收客户端的连接并发 ''' client import socket import time client = socket.socket() clie ...

  9. Linux是一个基于POSIX和Unix的多用户、多任务、支持多线程和多CPU的性能稳定的操作系统,可免费使用并自由传播。

    Linux是一个基于POSIX和Unix的多用户.多任务.支持多线程和多CPU的性能稳定的操作系统,可免费使用并自由传播. Linux是众多操作系统之一 , 目前流行的服务器和 PC 端操作系统有 L ...

  10. 一个基于mysql构建的队列表

    通常大家都会使用redis作为应用的任务队列表,redis的List结构,在一段进行任务的插入,在另一端进行任务的提取. 任务的插入 $redis->lPush("key:task:l ...

随机推荐

  1. CentOS 6.5快速部署HTTP WEB服务器和FTP服务器

    CentOS 6.5快速部署HTTP WEB服务器和FTP服务器 时间:2014-03-29    来源:服务器之家    投稿:root    点击:210次 [题记]本文使用CentOS 6.5m ...

  2. CENTOS 6.4 编译安装APACHE PHP MYSQL ZEND【转载未测试】

    CENTOS 6.4 编译安装APACHE PHP MYSQL ZEND 由 cache 发布于 WWW 2013-07-21 [ 5560 ] 次浏览 [ 0 ] 条评论 标签: LAMP 搞网站跑 ...

  3. 重学c#系列——DiagnosticListener [三十五]

    前言 简单介绍一下DiagnosticListener,一个比较常见的事件通知模型,可以说是事件发布订阅模型,常用于监控. 正文 直接编写代码: using System.Diagnostics; p ...

  4. apache 服务器配置常用知识点合集

    前言 因为当年周围同学都在学php,最为简单的就是学php 好就业啊,写个一些php,最后放弃了,apache也看了两眼吧.下面是我使用有记录的,没有记录的我后面会补上. 正文 域名配置 1.取消 N ...

  5. Java:得到指定年份、月份、周次的最后一天

    使用Java的工具类Calendar 通过Calendar可以进行很多的日期操作 /** * 得到指定年份的最后一天 * @param year */ public static void getLa ...

  6. 如何实现数据库数据到Abp vnext实体对象的同步?以及代码生成工具

    在采用了EF Core的Code First方式下,如果你在数据库中直接添加了新表或存储过程,你需要在项目代码中手动反向工程这些数据库的更改,以保持Code First的代码与数据库同步.这种情况可以 ...

  7. 《c#高级编程》第5章C#5.0中的更改(十一)——字符串插值

    在 C# 5 中,引入了字符串插值(string interpolation)语法,它提供了一种简单.直观的方式来将变量的值嵌入到字符串中.在以前的版本中,我们需要使用字符串格式化功能来实现这个目的, ...

  8. SQL 开发任务超 50% !滴滴实时计算的演进与优化

    摘要:Apache Flink 是一个分布式大数据处理引擎,可对有限数据流和无限数据流进行有状态计算.可部署在各种集群环境,对各种大小的数据规模进行快速计算.滴滴基于 Apache Flink 做了大 ...

  9. 如何用 Serverless 低成本打造个人专属网盘?

    ​简介:想要做个网盘不知如何开始,不妨花3分钟读读这篇,看看如何借助 Serverless ,低成本的做一个"不限制网速.无限扩展.同时支持数百种文件格式在线预览.编辑.协作"的专 ...

  10. WPF自定义控件的三种方式

    ​简介: 某些场景下,我们确实需要创建新的控件.此时,理解 WPF不同控件的创建方法就显得非常重要. WPF 提供3个用于创建控件的方法,每个方法都提供不同的灵活度. WPF控件可以通过数据模型(Da ...