re-common 10.0.37__py3-none-any.whl → 10.0.39__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- re_common/baselibrary/__init__.py +4 -4
- re_common/baselibrary/baseabs/__init__.py +6 -6
- re_common/baselibrary/baseabs/baseabs.py +26 -26
- re_common/baselibrary/database/mbuilder.py +132 -132
- re_common/baselibrary/database/moudle.py +93 -93
- re_common/baselibrary/database/msqlite3.py +194 -194
- re_common/baselibrary/database/mysql.py +169 -169
- re_common/baselibrary/database/sql_factory.py +26 -26
- re_common/baselibrary/mthread/MThreadingRun.py +486 -486
- re_common/baselibrary/mthread/MThreadingRunEvent.py +349 -349
- re_common/baselibrary/mthread/__init__.py +2 -2
- re_common/baselibrary/mthread/mythreading.py +695 -695
- re_common/baselibrary/pakge_other/socks.py +404 -404
- re_common/baselibrary/readconfig/config_factory.py +18 -18
- re_common/baselibrary/readconfig/ini_config.py +317 -317
- re_common/baselibrary/readconfig/toml_config.py +49 -49
- re_common/baselibrary/temporary/envdata.py +36 -36
- re_common/baselibrary/tools/all_requests/aiohttp_request.py +118 -118
- re_common/baselibrary/tools/all_requests/httpx_requet.py +102 -102
- re_common/baselibrary/tools/all_requests/mrequest.py +412 -412
- re_common/baselibrary/tools/all_requests/requests_request.py +81 -81
- re_common/baselibrary/tools/batch_compre/bijiao_batch.py +31 -31
- re_common/baselibrary/tools/contrast_db3.py +123 -123
- re_common/baselibrary/tools/copy_file.py +39 -39
- re_common/baselibrary/tools/db3_2_sizedb3.py +102 -102
- re_common/baselibrary/tools/foreachgz.py +39 -39
- re_common/baselibrary/tools/get_attr.py +10 -10
- re_common/baselibrary/tools/image_to_pdf.py +61 -61
- re_common/baselibrary/tools/java_code_deal.py +139 -139
- re_common/baselibrary/tools/javacode.py +79 -79
- re_common/baselibrary/tools/mdb_db3.py +48 -48
- re_common/baselibrary/tools/merge_file.py +171 -171
- re_common/baselibrary/tools/merge_gz_file.py +165 -165
- re_common/baselibrary/tools/mhdfstools/down_hdfs_files.py +42 -42
- re_common/baselibrary/tools/mhdfstools/hdfst.py +42 -42
- re_common/baselibrary/tools/mhdfstools/up_hdfs_files.py +38 -38
- re_common/baselibrary/tools/mongo_tools.py +50 -50
- re_common/baselibrary/tools/move_file.py +170 -170
- re_common/baselibrary/tools/move_mongo/mongo_table_to_file.py +63 -63
- re_common/baselibrary/tools/move_mongo/move_mongo_table.py +354 -354
- re_common/baselibrary/tools/move_mongo/use_mttf.py +18 -18
- re_common/baselibrary/tools/move_mongo/use_mv.py +93 -93
- re_common/baselibrary/tools/mpandas/mpandasreadexcel.py +125 -125
- re_common/baselibrary/tools/mpandas/pandas_visualization.py +7 -7
- re_common/baselibrary/tools/myparsel.py +104 -104
- re_common/baselibrary/tools/rename_dir_file.py +37 -37
- re_common/baselibrary/tools/sequoiadb_utils.py +398 -398
- re_common/baselibrary/tools/split_line_to_many.py +25 -25
- re_common/baselibrary/tools/stringtodicts.py +33 -33
- re_common/baselibrary/tools/workwechant_bot.py +84 -84
- re_common/baselibrary/utils/baseaiohttp.py +296 -296
- re_common/baselibrary/utils/baseaiomysql.py +87 -87
- re_common/baselibrary/utils/baseallstep.py +191 -191
- re_common/baselibrary/utils/baseavro.py +19 -19
- re_common/baselibrary/utils/baseboto3.py +291 -291
- re_common/baselibrary/utils/basecsv.py +32 -32
- re_common/baselibrary/utils/basedict.py +133 -133
- re_common/baselibrary/utils/basedir.py +241 -241
- re_common/baselibrary/utils/baseencode.py +351 -351
- re_common/baselibrary/utils/baseencoding.py +28 -28
- re_common/baselibrary/utils/baseesdsl.py +86 -86
- re_common/baselibrary/utils/baseexcel.py +264 -264
- re_common/baselibrary/utils/baseexcept.py +109 -109
- re_common/baselibrary/utils/basefile.py +654 -654
- re_common/baselibrary/utils/baseftp.py +214 -214
- re_common/baselibrary/utils/basegzip.py +60 -60
- re_common/baselibrary/utils/basehdfs.py +135 -135
- re_common/baselibrary/utils/basehttpx.py +268 -268
- re_common/baselibrary/utils/baseip.py +87 -87
- re_common/baselibrary/utils/basejson.py +2 -2
- re_common/baselibrary/utils/baselist.py +32 -32
- re_common/baselibrary/utils/basemotor.py +190 -190
- re_common/baselibrary/utils/basemssql.py +98 -98
- re_common/baselibrary/utils/baseodbc.py +113 -113
- re_common/baselibrary/utils/basepandas.py +302 -302
- re_common/baselibrary/utils/basepeewee.py +11 -11
- re_common/baselibrary/utils/basepika.py +180 -180
- re_common/baselibrary/utils/basepydash.py +143 -143
- re_common/baselibrary/utils/basepymongo.py +230 -230
- re_common/baselibrary/utils/basequeue.py +22 -22
- re_common/baselibrary/utils/baserar.py +57 -57
- re_common/baselibrary/utils/baserequest.py +279 -279
- re_common/baselibrary/utils/baseset.py +8 -8
- re_common/baselibrary/utils/basesmb.py +403 -403
- re_common/baselibrary/utils/basestring.py +382 -382
- re_common/baselibrary/utils/basetime.py +320 -320
- re_common/baselibrary/utils/baseurl.py +121 -121
- re_common/baselibrary/utils/basezip.py +57 -57
- re_common/baselibrary/utils/core/__init__.py +7 -7
- re_common/baselibrary/utils/core/bottomutils.py +18 -18
- re_common/baselibrary/utils/core/mdeprecated.py +327 -327
- re_common/baselibrary/utils/core/mlamada.py +16 -16
- re_common/baselibrary/utils/core/msginfo.py +25 -25
- re_common/baselibrary/utils/core/requests_core.py +103 -103
- re_common/baselibrary/utils/fateadm.py +429 -429
- re_common/baselibrary/utils/importfun.py +123 -123
- re_common/baselibrary/utils/mfaker.py +57 -57
- re_common/baselibrary/utils/my_abc/__init__.py +3 -3
- re_common/baselibrary/utils/my_abc/better_abc.py +32 -32
- re_common/baselibrary/utils/mylogger.py +414 -414
- re_common/baselibrary/utils/myredisclient.py +861 -861
- re_common/baselibrary/utils/pipupgrade.py +21 -21
- re_common/baselibrary/utils/ringlist.py +85 -85
- re_common/baselibrary/utils/version_compare.py +36 -36
- re_common/baselibrary/utils/ydmhttp.py +126 -126
- re_common/facade/lazy_import.py +11 -11
- re_common/facade/loggerfacade.py +25 -25
- re_common/facade/mysqlfacade.py +467 -467
- re_common/facade/now.py +31 -31
- re_common/facade/sqlite3facade.py +257 -257
- re_common/facade/use/mq_use_facade.py +83 -83
- re_common/facade/use/proxy_use_facade.py +19 -19
- re_common/libtest/base_dict_test.py +19 -19
- re_common/libtest/baseavro_test.py +13 -13
- re_common/libtest/basefile_test.py +14 -14
- re_common/libtest/basemssql_test.py +77 -77
- re_common/libtest/baseodbc_test.py +7 -7
- re_common/libtest/basepandas_test.py +38 -38
- re_common/libtest/get_attr_test/get_attr_test_settings.py +14 -14
- re_common/libtest/get_attr_test/settings.py +54 -54
- re_common/libtest/idencode_test.py +53 -53
- re_common/libtest/iniconfig_test.py +35 -35
- re_common/libtest/ip_test.py +34 -34
- re_common/libtest/merge_file_test.py +20 -20
- re_common/libtest/mfaker_test.py +8 -8
- re_common/libtest/mm3_test.py +31 -31
- re_common/libtest/mylogger_test.py +88 -88
- re_common/libtest/myparsel_test.py +27 -27
- re_common/libtest/mysql_test.py +151 -151
- re_common/libtest/pymongo_test.py +21 -21
- re_common/libtest/split_test.py +11 -11
- re_common/libtest/sqlite3_merge_test.py +5 -5
- re_common/libtest/sqlite3_test.py +34 -34
- re_common/libtest/tomlconfig_test.py +30 -30
- re_common/libtest/use_tools_test/__init__.py +2 -2
- re_common/libtest/user/__init__.py +4 -4
- re_common/studio/__init__.py +4 -4
- re_common/studio/assignment_expressions.py +36 -36
- re_common/studio/mydash/test1.py +18 -18
- re_common/studio/pydashstudio/first.py +9 -9
- re_common/studio/streamlitstudio/first_app.py +65 -65
- re_common/studio/streamlitstudio/uber_pickups.py +23 -23
- re_common/studio/test.py +18 -18
- re_common/v2/baselibrary/business_utils/BusinessStringUtil.py +219 -219
- re_common/v2/baselibrary/business_utils/baseencodeid.py +100 -100
- re_common/v2/baselibrary/business_utils/full_doi_path.py +116 -116
- re_common/v2/baselibrary/business_utils/rel_tools.py +6 -6
- re_common/v2/baselibrary/decorators/utils.py +59 -59
- re_common/v2/baselibrary/helpers/search_packge/NearestNeighbors_test.py +105 -105
- re_common/v2/baselibrary/helpers/search_packge/fit_text_match.py +253 -253
- re_common/v2/baselibrary/helpers/search_packge/scikit_learn_text_matcher.py +260 -260
- re_common/v2/baselibrary/helpers/search_packge/test.py +1 -1
- re_common/v2/baselibrary/s3object/baseboto3.py +230 -230
- re_common/v2/baselibrary/tools/WeChatRobot.py +95 -95
- re_common/v2/baselibrary/tools/ac_ahocorasick.py +75 -75
- re_common/v2/baselibrary/tools/concurrency.py +35 -35
- re_common/v2/baselibrary/tools/data_processer/base.py +53 -53
- re_common/v2/baselibrary/tools/data_processer/data_processer.py +508 -508
- re_common/v2/baselibrary/tools/data_processer/data_reader.py +187 -187
- re_common/v2/baselibrary/tools/data_processer/data_writer.py +38 -38
- re_common/v2/baselibrary/tools/dict_tools.py +44 -44
- re_common/v2/baselibrary/tools/dolphinscheduler.py +187 -187
- re_common/v2/baselibrary/tools/hdfs_base_processor.py +204 -204
- re_common/v2/baselibrary/tools/hdfs_bulk_processor.py +67 -67
- re_common/v2/baselibrary/tools/hdfs_data_processer.py +338 -338
- re_common/v2/baselibrary/tools/hdfs_line_processor.py +74 -74
- re_common/v2/baselibrary/tools/list_tools.py +69 -69
- re_common/v2/baselibrary/tools/resume_tracker.py +94 -94
- re_common/v2/baselibrary/tools/search_hash_tools.py +54 -54
- re_common/v2/baselibrary/tools/text_matcher.py +326 -326
- re_common/v2/baselibrary/tools/unionfind_tools.py +60 -60
- re_common/v2/baselibrary/utils/BusinessStringUtil.py +196 -196
- re_common/v2/baselibrary/utils/api_net_utils.py +270 -270
- re_common/v2/baselibrary/utils/author_smi.py +361 -361
- re_common/v2/baselibrary/utils/base_string_similarity.py +158 -158
- re_common/v2/baselibrary/utils/basedict.py +37 -37
- re_common/v2/baselibrary/utils/basehdfs.py +163 -163
- re_common/v2/baselibrary/utils/basepika.py +180 -180
- re_common/v2/baselibrary/utils/basetime.py +77 -77
- re_common/v2/baselibrary/utils/db.py +156 -156
- re_common/v2/baselibrary/utils/json_cls.py +16 -16
- re_common/v2/baselibrary/utils/mq.py +83 -83
- re_common/v2/baselibrary/utils/n_ary_expression_tree.py +243 -243
- re_common/v2/baselibrary/utils/string_bool.py +186 -186
- re_common/v2/baselibrary/utils/string_clear.py +246 -246
- re_common/v2/baselibrary/utils/string_smi.py +18 -18
- re_common/v2/baselibrary/utils/stringutils.py +271 -278
- re_common/vip/base_step_process.py +11 -11
- re_common/vip/baseencodeid.py +90 -90
- re_common/vip/changetaskname.py +28 -28
- re_common/vip/core_var.py +24 -24
- re_common/vip/mmh3Hash.py +89 -89
- re_common/vip/proxy/allproxys.py +127 -127
- re_common/vip/proxy/allproxys_thread.py +159 -159
- re_common/vip/proxy/cnki_proxy.py +153 -153
- re_common/vip/proxy/kuaidaili.py +87 -87
- re_common/vip/proxy/proxy_all.py +113 -113
- re_common/vip/proxy/update_kuaidaili_0.py +42 -42
- re_common/vip/proxy/wanfang_proxy.py +152 -152
- re_common/vip/proxy/wp_proxy_all.py +181 -181
- re_common/vip/read_rawid_to_txt.py +91 -91
- re_common/vip/title/__init__.py +5 -5
- re_common/vip/title/transform/TransformBookTitleToZt.py +125 -125
- re_common/vip/title/transform/TransformConferenceTitleToZt.py +139 -139
- re_common/vip/title/transform/TransformCstadTitleToZt.py +195 -195
- re_common/vip/title/transform/TransformJournalTitleToZt.py +203 -203
- re_common/vip/title/transform/TransformPatentTitleToZt.py +132 -132
- re_common/vip/title/transform/TransformRegulationTitleToZt.py +114 -114
- re_common/vip/title/transform/TransformStandardTitleToZt.py +135 -135
- re_common/vip/title/transform/TransformThesisTitleToZt.py +135 -135
- re_common/vip/title/transform/__init__.py +10 -10
- {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/LICENSE +201 -201
- {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/METADATA +16 -16
- re_common-10.0.39.dist-info/RECORD +248 -0
- {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/WHEEL +1 -1
- re_common-10.0.37.dist-info/RECORD +0 -248
- {re_common-10.0.37.dist-info → re_common-10.0.39.dist-info}/top_level.txt +0 -0
|
@@ -1,695 +1,695 @@
|
|
|
1
|
-
import ctypes
|
|
2
|
-
import functools
|
|
3
|
-
import inspect
|
|
4
|
-
import sys
|
|
5
|
-
import threading
|
|
6
|
-
# 创建一个有4个线程的线程池
|
|
7
|
-
import time
|
|
8
|
-
import traceback
|
|
9
|
-
from threading import Thread
|
|
10
|
-
|
|
11
|
-
from re_common.baselibrary.utils.basequeue import BaseQueue
|
|
12
|
-
from re_common.facade.loggerfacade import get_streamlogger
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class ThreadInfo(object):
|
|
16
|
-
"""
|
|
17
|
-
该类存储着线程的信息,原本使用一个空的字典进行存储,
|
|
18
|
-
但字典的结构不可见且不清晰,故使用类进行结构化展示
|
|
19
|
-
"""
|
|
20
|
-
|
|
21
|
-
def __init__(self):
|
|
22
|
-
self.is_restart = True
|
|
23
|
-
|
|
24
|
-
def set_thread(self, thread):
|
|
25
|
-
self.thread = thread
|
|
26
|
-
return self
|
|
27
|
-
|
|
28
|
-
def get_thread(self):
|
|
29
|
-
return self.thread
|
|
30
|
-
|
|
31
|
-
def set_thread_name(self, thread_name):
|
|
32
|
-
self.thread_name = thread_name
|
|
33
|
-
return self
|
|
34
|
-
|
|
35
|
-
def get_thread_name(self):
|
|
36
|
-
return self.thread_name
|
|
37
|
-
|
|
38
|
-
def set_kwargs(self, kwargs):
|
|
39
|
-
self.kwargs = kwargs
|
|
40
|
-
return self
|
|
41
|
-
|
|
42
|
-
def get_kwargs(self):
|
|
43
|
-
return self.kwargs
|
|
44
|
-
|
|
45
|
-
def set_args(self, args):
|
|
46
|
-
self.args = args
|
|
47
|
-
return self
|
|
48
|
-
|
|
49
|
-
def get_args(self):
|
|
50
|
-
return self.args
|
|
51
|
-
|
|
52
|
-
def set_dicts(self, dicts):
|
|
53
|
-
self.dicts = dicts
|
|
54
|
-
return self
|
|
55
|
-
|
|
56
|
-
def get_dicts(self):
|
|
57
|
-
return self.dicts
|
|
58
|
-
|
|
59
|
-
def set_is_restart(self, is_restart: bool):
|
|
60
|
-
"""
|
|
61
|
-
设置该线程是否应该重启
|
|
62
|
-
:param is_restart:
|
|
63
|
-
:return:
|
|
64
|
-
"""
|
|
65
|
-
self.is_restart = is_restart
|
|
66
|
-
return self
|
|
67
|
-
|
|
68
|
-
def get_is_restart(self):
|
|
69
|
-
return self.is_restart
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class ThreadPoolManger(object):
|
|
73
|
-
"""
|
|
74
|
-
线程池管理器
|
|
75
|
-
"""
|
|
76
|
-
# 线程锁
|
|
77
|
-
lock = threading.Lock()
|
|
78
|
-
|
|
79
|
-
def __init__(self, thread_num, logger=None):
|
|
80
|
-
if logger:
|
|
81
|
-
self.logger = logger
|
|
82
|
-
else:
|
|
83
|
-
self.logger = get_streamlogger()
|
|
84
|
-
self.prefix = "my_threading_task_"
|
|
85
|
-
# 任务队列
|
|
86
|
-
self.work_queue = BaseQueue(100)
|
|
87
|
-
# 结果队列 有时候结果需要在主线程处理或单独线程处理时使用
|
|
88
|
-
self.result_queue = BaseQueue(100)
|
|
89
|
-
# 线程队列 主要管线程间的通信
|
|
90
|
-
self.thread_queue = BaseQueue(10)
|
|
91
|
-
# 线程池 里面保存着线程对象
|
|
92
|
-
# self.threadpool = list()
|
|
93
|
-
# # 线程名列表
|
|
94
|
-
# self.initThreadsName = set()
|
|
95
|
-
# 应该赋予一个方法 用于回调
|
|
96
|
-
self.callback = None
|
|
97
|
-
# 线程池的字典 有时候需要在线程池中维护一些数据,所以没有采用原来的只维护线程对象
|
|
98
|
-
self.thread_pool_dicts = {}
|
|
99
|
-
|
|
100
|
-
# 线程数量 反馈当前工作线程数量
|
|
101
|
-
self.thread_num = thread_num
|
|
102
|
-
# 工作线程定量 该变量是为了维持线程的数量一定
|
|
103
|
-
self.max_workers = thread_num
|
|
104
|
-
# 是否是动态最大值
|
|
105
|
-
self.is_static_max = True
|
|
106
|
-
# 线程的参数 定义线程时使用
|
|
107
|
-
self.args = ()
|
|
108
|
-
self.kwargs = {}
|
|
109
|
-
|
|
110
|
-
# # 各种非工作线程池
|
|
111
|
-
# self.especial_thread_pool = list()
|
|
112
|
-
# # 特殊线程名
|
|
113
|
-
# self.especial_threads_Name = set()
|
|
114
|
-
|
|
115
|
-
# 各种非工作线程池 特殊线程名
|
|
116
|
-
self.especial_thread_pool_dicts = {}
|
|
117
|
-
|
|
118
|
-
# 该标志将用于sql间的同步 现在发现一个问题 在 线程中执行select会出现
|
|
119
|
-
# Command Out of Sync 错误 所以启用这个信号
|
|
120
|
-
# 这个错误表示 对于同一个连接 在不同线程中当一个线程发出sql且没有返回结果期间,
|
|
121
|
-
# 另一个线程页发出了请求,这时mysql的第一个请求在结果缓存中还没有返回 会冲突报错
|
|
122
|
-
# 这里主要是设置任务和处理结果用到同一个连接导致
|
|
123
|
-
self.event = threading.Event()
|
|
124
|
-
self.event_set()
|
|
125
|
-
# 独立的线程变量,很多时候 多线程变量是共享且线程不安全的,
|
|
126
|
-
# 该变量保证了线程内变量的安全与threadVal的概念相同
|
|
127
|
-
self.localVal = threading.local()
|
|
128
|
-
|
|
129
|
-
# # 初始化线程到线程池
|
|
130
|
-
self.__init_threading_pool(self.thread_num)
|
|
131
|
-
|
|
132
|
-
@classmethod
|
|
133
|
-
def thread_lock(cls, func):
|
|
134
|
-
@functools.wraps(func)
|
|
135
|
-
def wrapper(*args, **kwargs):
|
|
136
|
-
try:
|
|
137
|
-
cls.lock.acquire()
|
|
138
|
-
return func(*args, **kwargs)
|
|
139
|
-
finally:
|
|
140
|
-
cls.lock.release()
|
|
141
|
-
|
|
142
|
-
return wrapper
|
|
143
|
-
|
|
144
|
-
def set_args(self, args):
|
|
145
|
-
"""
|
|
146
|
-
设置元组参数
|
|
147
|
-
:param args:
|
|
148
|
-
:return:
|
|
149
|
-
"""
|
|
150
|
-
self.args = args
|
|
151
|
-
|
|
152
|
-
def set_kwargs(self, kwargs):
|
|
153
|
-
"""
|
|
154
|
-
设置字典参数
|
|
155
|
-
:param kwargs:
|
|
156
|
-
:return:
|
|
157
|
-
"""
|
|
158
|
-
self.kwargs = kwargs
|
|
159
|
-
|
|
160
|
-
def set_is_static_max(self, is_static_max):
|
|
161
|
-
"""
|
|
162
|
-
设置是否允许
|
|
163
|
-
:param is_static_max:
|
|
164
|
-
:return:
|
|
165
|
-
"""
|
|
166
|
-
self.is_static_max = is_static_max
|
|
167
|
-
|
|
168
|
-
def set_max_workers(self, num):
|
|
169
|
-
"""
|
|
170
|
-
如果线程数是动态的,就允许设置大小
|
|
171
|
-
:param num:
|
|
172
|
-
:return:
|
|
173
|
-
"""
|
|
174
|
-
if self.is_static_max:
|
|
175
|
-
self.logger.info("是静态最大线程数,不能对最大线程数进行设置")
|
|
176
|
-
else:
|
|
177
|
-
self.max_workers = num
|
|
178
|
-
|
|
179
|
-
def get_max_workers(self):
|
|
180
|
-
return self.max_workers
|
|
181
|
-
|
|
182
|
-
def get_localVal(self):
|
|
183
|
-
"""
|
|
184
|
-
获取线程独立变量
|
|
185
|
-
:return:
|
|
186
|
-
"""
|
|
187
|
-
return self.localVal
|
|
188
|
-
|
|
189
|
-
def set_localVal(self, val):
|
|
190
|
-
self.localVal = val
|
|
191
|
-
|
|
192
|
-
def set_callback(self, callback):
|
|
193
|
-
self.callback = callback
|
|
194
|
-
|
|
195
|
-
def event_set(self):
|
|
196
|
-
"""
|
|
197
|
-
设置event 允许wait继续运行 状态为True
|
|
198
|
-
:return:
|
|
199
|
-
"""
|
|
200
|
-
self.event.set()
|
|
201
|
-
|
|
202
|
-
def event_clear(self):
|
|
203
|
-
"""
|
|
204
|
-
设置值为False 不允许运行其他线程
|
|
205
|
-
:return:
|
|
206
|
-
"""
|
|
207
|
-
self.event.clear()
|
|
208
|
-
|
|
209
|
-
def event_is_set(self):
|
|
210
|
-
"""
|
|
211
|
-
返回标志
|
|
212
|
-
:return:
|
|
213
|
-
"""
|
|
214
|
-
return self.event.is_set()
|
|
215
|
-
|
|
216
|
-
def event_wait(self, timeout=None):
|
|
217
|
-
self.event.wait(timeout)
|
|
218
|
-
|
|
219
|
-
def set_thread_name_prefix(self, prefix):
|
|
220
|
-
self.prefix = prefix
|
|
221
|
-
|
|
222
|
-
def __init_threading_pool(self, thread_num):
|
|
223
|
-
"""
|
|
224
|
-
初始化线程池,创建指定数量的线程池
|
|
225
|
-
:param thread_num:
|
|
226
|
-
:return:
|
|
227
|
-
"""
|
|
228
|
-
self.logger.info("初始化工作线程数量为:%d" % thread_num)
|
|
229
|
-
for i in range(int(thread_num)):
|
|
230
|
-
# 新建一个线程
|
|
231
|
-
thread = ThreadManager(self.work_queue,
|
|
232
|
-
self.result_queue,
|
|
233
|
-
self.thread_queue,
|
|
234
|
-
self.logger,
|
|
235
|
-
args=self.args,
|
|
236
|
-
kwargs=self.kwargs)
|
|
237
|
-
# 线程名
|
|
238
|
-
threadName = "{}{}".format(self.prefix, i + 1)
|
|
239
|
-
if threadName in self.thread_pool_dicts:
|
|
240
|
-
self.logger.warn("线程名%s在线程池中已经存在,跳过" % threadName)
|
|
241
|
-
else:
|
|
242
|
-
# 设置线程名
|
|
243
|
-
thread.setName(threadName)
|
|
244
|
-
self.set_thread_pool_dicts(self.thread_pool_dicts, threadName, thread, self.args, self.kwargs)
|
|
245
|
-
|
|
246
|
-
def set_thread_pool_dicts(self, thread_pool_dicts, threadName, thread, args, kwargs):
|
|
247
|
-
"""
|
|
248
|
-
这里调用了一个钩子函数 可以在dicts中加入其他参数
|
|
249
|
-
:param thread_pool_dicts: 线程池字典对象
|
|
250
|
-
:param threadName: 线程名
|
|
251
|
-
:param thread: 线程
|
|
252
|
-
:param args:
|
|
253
|
-
:param kwargs:
|
|
254
|
-
:return:
|
|
255
|
-
"""
|
|
256
|
-
threadinfo = ThreadInfo()
|
|
257
|
-
threadinfo.set_thread(thread)
|
|
258
|
-
threadinfo.set_kwargs(kwargs)
|
|
259
|
-
threadinfo.set_args(args)
|
|
260
|
-
threadinfo.set_thread_name(threadName)
|
|
261
|
-
if self.callback:
|
|
262
|
-
# 对象使用
|
|
263
|
-
dicts = self.callback(threadinfo)
|
|
264
|
-
else:
|
|
265
|
-
# 继承时使用
|
|
266
|
-
dicts = self.thread_pool_hook(threadinfo)
|
|
267
|
-
if not dicts:
|
|
268
|
-
dicts = {}
|
|
269
|
-
threadinfo.set_dicts(dicts)
|
|
270
|
-
thread_pool_dicts[threadName] = threadinfo
|
|
271
|
-
|
|
272
|
-
def thread_pool_hook(self, threadinfo: ThreadInfo) -> dict:
|
|
273
|
-
"""
|
|
274
|
-
钩子函数 可以被重写
|
|
275
|
-
主要重写里面的dicts部分
|
|
276
|
-
:return:
|
|
277
|
-
"""
|
|
278
|
-
return {}
|
|
279
|
-
|
|
280
|
-
def reload_thread(self, thread_name):
|
|
281
|
-
"""
|
|
282
|
-
通过线程名重启线程
|
|
283
|
-
:param thread_name:
|
|
284
|
-
:return:
|
|
285
|
-
"""
|
|
286
|
-
is_start = False
|
|
287
|
-
if thread_name in self.thread_pool_dicts:
|
|
288
|
-
self.logger.info("{}线程名存在".format(thread_name))
|
|
289
|
-
if self.thread_pool_dicts[thread_name].get_thread().is_alive():
|
|
290
|
-
self.logger.info("{}线程名是存活的".format(thread_name))
|
|
291
|
-
is_start = True
|
|
292
|
-
else:
|
|
293
|
-
self.logger.info("{}线程名是没有存活 需要重启".format(thread_name))
|
|
294
|
-
|
|
295
|
-
if not is_start:
|
|
296
|
-
args = self.thread_pool_dicts[thread_name].get_args()
|
|
297
|
-
kwargs = self.thread_pool_dicts[thread_name].get_kwargs()
|
|
298
|
-
self.logger.info("新建或重启线程{}".format(thread_name))
|
|
299
|
-
# 新建一个线程
|
|
300
|
-
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue, self.logger, args=args,
|
|
301
|
-
kwargs=kwargs)
|
|
302
|
-
# 设置线程名
|
|
303
|
-
thread.setName(thread_name)
|
|
304
|
-
# # 加入线程池
|
|
305
|
-
# self.threadpool.append(thread)
|
|
306
|
-
self.set_thread_pool_dicts(self.thread_pool_dicts, thread_name, thread, args, kwargs)
|
|
307
|
-
thread.start()
|
|
308
|
-
|
|
309
|
-
def add_thread(self, thread_num):
|
|
310
|
-
"""
|
|
311
|
-
添加线程,thread_num是添加线程的数量
|
|
312
|
-
:param thread_num:
|
|
313
|
-
:return:
|
|
314
|
-
"""
|
|
315
|
-
# 判断可开线程的数量
|
|
316
|
-
if self.thread_num < self.max_workers:
|
|
317
|
-
if self.max_workers - self.thread_num < thread_num:
|
|
318
|
-
thread_num = self.max_workers - self.thread_num
|
|
319
|
-
else:
|
|
320
|
-
self.logger.info("线程已达到最大量,不能再新开线程")
|
|
321
|
-
return False
|
|
322
|
-
# 添加新的线程
|
|
323
|
-
count = 0
|
|
324
|
-
num = 0
|
|
325
|
-
while thread_num > count:
|
|
326
|
-
num += 1
|
|
327
|
-
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue,
|
|
328
|
-
self.logger,
|
|
329
|
-
args=self.args,
|
|
330
|
-
kwargs=self.kwargs)
|
|
331
|
-
thread_name = "{}{}".format(self.prefix, num)
|
|
332
|
-
if thread_name in self.thread_pool_dicts:
|
|
333
|
-
continue
|
|
334
|
-
thread.setName(thread_name)
|
|
335
|
-
self.logger.info("添加一个线程{}".format(thread_name))
|
|
336
|
-
self.set_thread_pool_dicts(self.thread_pool_dicts, thread_name, thread, self.args, self.kwargs)
|
|
337
|
-
count += 1
|
|
338
|
-
self.get_thread_num()
|
|
339
|
-
return True
|
|
340
|
-
|
|
341
|
-
def delete_thread(self, thread_num):
|
|
342
|
-
"""
|
|
343
|
-
删除多少个线程,thread_num为删除数量
|
|
344
|
-
:param thread_num:
|
|
345
|
-
:return:
|
|
346
|
-
"""
|
|
347
|
-
try:
|
|
348
|
-
i = 0
|
|
349
|
-
for key in list(self.thread_pool_dicts.keys()):
|
|
350
|
-
thread = self.thread_pool_dicts[key].get_thread()
|
|
351
|
-
if not thread.runstatus:
|
|
352
|
-
# 优先删除处于等待任务的线程
|
|
353
|
-
thread.thread_delete = True
|
|
354
|
-
self.stop_thread(thread)
|
|
355
|
-
del self.thread_pool_dicts[key]
|
|
356
|
-
i += 1
|
|
357
|
-
elif thread.threadval.thread_delete:
|
|
358
|
-
# 删除该线程 表示线程池想删除(删除逻辑为我想删除 且程序内部允许删除时删除)
|
|
359
|
-
thread.thread_delete = True
|
|
360
|
-
del self.thread_pool_dicts[key]
|
|
361
|
-
i += 1
|
|
362
|
-
if i >= thread_num:
|
|
363
|
-
break
|
|
364
|
-
except IndexError:
|
|
365
|
-
pass
|
|
366
|
-
self.get_thread_num()
|
|
367
|
-
|
|
368
|
-
def get_thread_num(self):
|
|
369
|
-
self.thread_num = len(self.thread_pool_dicts)
|
|
370
|
-
return self.thread_num
|
|
371
|
-
|
|
372
|
-
def set_thread_num(self, thread_num):
|
|
373
|
-
"""
|
|
374
|
-
设置当前线程数量 改设置保证了线程数量 多的会被删除,少的会被添加
|
|
375
|
-
:return:
|
|
376
|
-
"""
|
|
377
|
-
if thread_num > self.get_thread_num():
|
|
378
|
-
self.add_thread(thread_num - self.thread_num)
|
|
379
|
-
else:
|
|
380
|
-
self.delete_thread(self.get_thread_num() - thread_num)
|
|
381
|
-
# self.threadpool = self.threadpool[:int(thread_num)]
|
|
382
|
-
self.thread_num = thread_num
|
|
383
|
-
|
|
384
|
-
def add_super_thread(self, func, thread_name, mode="super", *args, **kwargs):
|
|
385
|
-
"""
|
|
386
|
-
添加一个线程,该线程直接由原生线程控制,
|
|
387
|
-
:param func:
|
|
388
|
-
:param thread_name:
|
|
389
|
-
:param args:
|
|
390
|
-
:param kwargs:
|
|
391
|
-
:return:
|
|
392
|
-
"""
|
|
393
|
-
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue,
|
|
394
|
-
self.logger,
|
|
395
|
-
target=func, name=thread_name,
|
|
396
|
-
args=args,
|
|
397
|
-
kwargs=kwargs)
|
|
398
|
-
thread.set_mode(mode)
|
|
399
|
-
return thread
|
|
400
|
-
|
|
401
|
-
def set_add_especial_thread(self, func, threadname, mode="super", *args, **kwargs):
|
|
402
|
-
"""
|
|
403
|
-
添加特殊的线程
|
|
404
|
-
:return:
|
|
405
|
-
"""
|
|
406
|
-
# 得到一个线程对象
|
|
407
|
-
thread = self.add_super_thread(func, threadname, mode, *args, **kwargs)
|
|
408
|
-
self.set_thread_pool_dicts(self.especial_thread_pool_dicts, threadname, thread, args, kwargs)
|
|
409
|
-
return thread
|
|
410
|
-
|
|
411
|
-
def add_job(self, func, *args, **kwargs):
|
|
412
|
-
"""
|
|
413
|
-
将任务放入队列,等待线程池阻塞读取,参数是被执行的函数和函数的参数
|
|
414
|
-
:param func:
|
|
415
|
-
:param args:
|
|
416
|
-
:param kwargs:
|
|
417
|
-
:return:
|
|
418
|
-
"""
|
|
419
|
-
self.work_queue.put((func, self.result_queue, args, kwargs))
|
|
420
|
-
|
|
421
|
-
def start(self):
|
|
422
|
-
for thread in self.thread_pool_dicts:
|
|
423
|
-
time.sleep(2)
|
|
424
|
-
if self.thread_pool_dicts[thread]:
|
|
425
|
-
thread = self.thread_pool_dicts[thread].get_thread()
|
|
426
|
-
if thread and not thread.is_alive():
|
|
427
|
-
thread.start()
|
|
428
|
-
|
|
429
|
-
def especial_start(self):
|
|
430
|
-
for threadname in self.especial_thread_pool_dicts:
|
|
431
|
-
if self.especial_thread_pool_dicts[threadname]:
|
|
432
|
-
threadinfo = self.especial_thread_pool_dicts[threadname]
|
|
433
|
-
thread = threadinfo.thread
|
|
434
|
-
if thread and not thread.is_alive():
|
|
435
|
-
self.logger.info("启动线程{}".format(thread.getName()))
|
|
436
|
-
thread.start()
|
|
437
|
-
else:
|
|
438
|
-
self.logger.info("启动线程{} 失败".format(thread.getName()))
|
|
439
|
-
|
|
440
|
-
def get_now_thread(self):
|
|
441
|
-
"""
|
|
442
|
-
获取进程中还存在的线程
|
|
443
|
-
:return:
|
|
444
|
-
"""
|
|
445
|
-
# 用来保存当前线程名称
|
|
446
|
-
nowThreadsName = []
|
|
447
|
-
# 获取当前线程名
|
|
448
|
-
now = threading.enumerate()
|
|
449
|
-
for i in now:
|
|
450
|
-
# 保存当前线程名称
|
|
451
|
-
nowThreadsName.append(i.getName())
|
|
452
|
-
return nowThreadsName
|
|
453
|
-
|
|
454
|
-
# 防止线程意外挂掉 挂掉线程重启
|
|
455
|
-
def checkThread(self):
|
|
456
|
-
nowThreadsName = self.get_now_thread()
|
|
457
|
-
# 循环线程池的key
|
|
458
|
-
for name in list(self.thread_pool_dicts.keys()):
|
|
459
|
-
# 取出线程对象
|
|
460
|
-
thread = self.thread_pool_dicts[name].get_thread()
|
|
461
|
-
# 如果线程字典为空 代表已被删除
|
|
462
|
-
if name in nowThreadsName and thread.is_alive():
|
|
463
|
-
pass # 当前某线程名包含在初始化线程组中,可以认为线程仍在运行
|
|
464
|
-
else:
|
|
465
|
-
self.reload_thread(name) # 重启线程
|
|
466
|
-
# 如果不是静态最大值 线程可以波动
|
|
467
|
-
if not self.is_static_max:
|
|
468
|
-
# 空闲线程
|
|
469
|
-
free_thread = 0
|
|
470
|
-
# 判断线程空闲情况
|
|
471
|
-
for name in list(self.thread_pool_dicts.keys()):
|
|
472
|
-
thread = self.thread_pool_dicts[name].get_thread()
|
|
473
|
-
if not thread.runstatus:
|
|
474
|
-
# 代表该线程等待工作队列,列入空闲线程
|
|
475
|
-
free_thread += 1
|
|
476
|
-
elif thread.threadval.thread_delete:
|
|
477
|
-
free_thread += 1
|
|
478
|
-
|
|
479
|
-
# 允许冗余2个工作线程 避免在零界点不停的创建,删除
|
|
480
|
-
if free_thread > 2:
|
|
481
|
-
self.max_workers = self.max_workers - (free_thread - 2)
|
|
482
|
-
|
|
483
|
-
# 判断是否需要删除线程
|
|
484
|
-
if len(self.thread_pool_dicts) > self.max_workers:
|
|
485
|
-
self.logger.info("线程池有{},最大线程数量{},调用删除线程程序".format(len(self.thread_pool_dicts), self.max_workers))
|
|
486
|
-
self.delete_thread(len(self.thread_pool_dicts) - self.max_workers)
|
|
487
|
-
|
|
488
|
-
self.logger.info("当前线程数量为{},线程为:{}".format(len(self.thread_pool_dicts), list(self.thread_pool_dicts.keys())))
|
|
489
|
-
|
|
490
|
-
def checkThreadRunFinish(self):
|
|
491
|
-
"""
|
|
492
|
-
通过等待的方式判断结束,等待是因为任务队列取出任务后在运行,还没放入结果队列
|
|
493
|
-
:return:
|
|
494
|
-
"""
|
|
495
|
-
self.logger.info("result_queue is empty:{}".format(self.result_queue.is_empty()))
|
|
496
|
-
self.logger.info("work_queue is empty:{}".format(self.work_queue.is_empty()))
|
|
497
|
-
if self.result_queue.is_empty() and self.work_queue.is_empty():
|
|
498
|
-
time.sleep(10)
|
|
499
|
-
t1 = self.result_queue.is_empty()
|
|
500
|
-
time.sleep(10)
|
|
501
|
-
t2 = self.result_queue.is_empty()
|
|
502
|
-
if t1 and t2:
|
|
503
|
-
if self.work_queue.is_empty():
|
|
504
|
-
return True
|
|
505
|
-
return False
|
|
506
|
-
return False
|
|
507
|
-
|
|
508
|
-
# 下面两个方法是强制退出线程的方法
|
|
509
|
-
def _async_raise(self, tid, exctype):
|
|
510
|
-
"""raises the exception, performs cleanup if needed"""
|
|
511
|
-
tid = ctypes.c_long(tid)
|
|
512
|
-
if not inspect.isclass(exctype):
|
|
513
|
-
exctype = type(exctype)
|
|
514
|
-
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
|
|
515
|
-
if res == 0:
|
|
516
|
-
raise ValueError("invalid thread id")
|
|
517
|
-
elif res != 1:
|
|
518
|
-
# """if it returns a number greater than one, you're in trouble,
|
|
519
|
-
# and you should call it again with exc=NULL to revert the effect"""
|
|
520
|
-
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
|
|
521
|
-
raise SystemError("PyThreadState_SetAsyncExc failed")
|
|
522
|
-
|
|
523
|
-
def stop_thread(self, thread):
|
|
524
|
-
if thread:
|
|
525
|
-
try:
|
|
526
|
-
self.logger.info("thread is {};thread.ident 的值为:{}".format(thread, thread.ident))
|
|
527
|
-
if thread.ident:
|
|
528
|
-
self._async_raise(thread.ident, SystemExit)
|
|
529
|
-
except ValueError as e:
|
|
530
|
-
self.logger.info("已经运行完毕 不需要删除了")
|
|
531
|
-
else:
|
|
532
|
-
self.logger.info("传入的线程对象为空,理论上不应该出现这种逻辑 结束程序检查逻辑")
|
|
533
|
-
sys.exit(-1)
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
class ThreadVal(object):
|
|
537
|
-
"""
|
|
538
|
-
该对象维护线程函数的变量以及与线程对象间的交互
|
|
539
|
-
"""
|
|
540
|
-
|
|
541
|
-
def __init__(self):
|
|
542
|
-
# 该线程是否被删除
|
|
543
|
-
self.thread_delete = False
|
|
544
|
-
# 线程初始化参数
|
|
545
|
-
self.args = ()
|
|
546
|
-
self.kwargs = None
|
|
547
|
-
self.result_queue = None
|
|
548
|
-
self.work_queue = None
|
|
549
|
-
|
|
550
|
-
def set_args(self, args):
|
|
551
|
-
self.args = args
|
|
552
|
-
|
|
553
|
-
def set_kwargs(self, kwargs):
|
|
554
|
-
self.kwargs = kwargs
|
|
555
|
-
|
|
556
|
-
def set_result_queue(self, result_queue):
|
|
557
|
-
self.result_queue = result_queue
|
|
558
|
-
|
|
559
|
-
def get_result_queue(self):
|
|
560
|
-
return self.result_queue
|
|
561
|
-
|
|
562
|
-
def set_work_queue(self, work_queue):
|
|
563
|
-
self.work_queue = work_queue
|
|
564
|
-
|
|
565
|
-
def get_work_queue(self):
|
|
566
|
-
return self.work_queue
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
class ThreadManager(Thread):
|
|
570
|
-
"""
|
|
571
|
-
定义线程类,继承threading.Thread
|
|
572
|
-
该类主要实现线程的运行
|
|
573
|
-
"""
|
|
574
|
-
|
|
575
|
-
def __init__(self, work_queue=None, result_queue=None, thread_queue=None, logger=None, group=None, target=None,
|
|
576
|
-
name=None, args=(), kwargs=None, daemon=True, mode="default"):
|
|
577
|
-
if mode == "default":
|
|
578
|
-
if work_queue is None or result_queue is None or thread_queue is None:
|
|
579
|
-
raise Exception("work_queue result_queue thread_queue 必须存在")
|
|
580
|
-
if args is None:
|
|
581
|
-
args = ()
|
|
582
|
-
# 线程本身的参数
|
|
583
|
-
Thread.__init__(self, group, target, name,
|
|
584
|
-
args, kwargs, daemon=daemon)
|
|
585
|
-
if kwargs is None:
|
|
586
|
-
kwargs = {}
|
|
587
|
-
if logger:
|
|
588
|
-
self.logger = logger
|
|
589
|
-
else:
|
|
590
|
-
self.logger = get_streamlogger()
|
|
591
|
-
self.target = target
|
|
592
|
-
self.kwargs = kwargs
|
|
593
|
-
self.args = args
|
|
594
|
-
# 接受两个队列 一个处理结果 一个发送任务
|
|
595
|
-
self.work_queue = work_queue
|
|
596
|
-
self.result_queue = result_queue
|
|
597
|
-
# 线程队列
|
|
598
|
-
self.thread_queue = thread_queue
|
|
599
|
-
# 主线程退出 该线程也会退出
|
|
600
|
-
self.daemon = daemon
|
|
601
|
-
# 一个标识 如果为False代表线程运行完毕等待新的任务到来,否则表示任务正在运行
|
|
602
|
-
# 这个标志是为了检查程序在运行中还是等待状态
|
|
603
|
-
self.runstatus = False
|
|
604
|
-
# 设置该标志是为了表示是否愿意被重新启动,因为有些线程只需要运行一次
|
|
605
|
-
# 而有的需要长期运行且有一定的重启机制(目前暂未启动该标志)
|
|
606
|
-
self.is_restart = True
|
|
607
|
-
# 为了兼容普通线程类模式 "default" 自己写的run 方法 "super": 父类的run方法
|
|
608
|
-
self.mode = mode
|
|
609
|
-
# 是否可以被删除 True 线程可以停止,False 不可以被停止 有时候我们需要删除一批线程 但是 线程不能中间
|
|
610
|
-
# 状态被删除 故需要设置该标志
|
|
611
|
-
self.thread_delete = False
|
|
612
|
-
# 线程内部的一个类对象 每个线程维护一个保证里面的数据线程安全,以后为每个线程提供服务
|
|
613
|
-
self.threadval = ThreadVal()
|
|
614
|
-
self.threadval.set_args(self.args)
|
|
615
|
-
self.threadval.set_kwargs(self.kwargs)
|
|
616
|
-
|
|
617
|
-
def get_runstatus(self):
|
|
618
|
-
return self.runstatus
|
|
619
|
-
|
|
620
|
-
def set_runstatus(self, runstatus):
|
|
621
|
-
self.runstatus = runstatus
|
|
622
|
-
|
|
623
|
-
def get_is_restart(self):
|
|
624
|
-
return self.is_restart
|
|
625
|
-
|
|
626
|
-
def set_is_restart(self, is_restart):
|
|
627
|
-
self.is_restart = is_restart
|
|
628
|
-
|
|
629
|
-
def set_mode(self, mode):
|
|
630
|
-
"""
|
|
631
|
-
设置运行模式 super or default
|
|
632
|
-
super 将方法直接传入target
|
|
633
|
-
default 使用自己封装的run
|
|
634
|
-
:param mode:
|
|
635
|
-
:return:
|
|
636
|
-
"""
|
|
637
|
-
self.mode = mode
|
|
638
|
-
|
|
639
|
-
def get_mode(self):
|
|
640
|
-
return self.mode
|
|
641
|
-
|
|
642
|
-
def run(self):
|
|
643
|
-
if self.mode == "default":
|
|
644
|
-
self.run_default()
|
|
645
|
-
elif self.mode == "mysuper":
|
|
646
|
-
self.run_arg()
|
|
647
|
-
elif self.mode == "super":
|
|
648
|
-
try:
|
|
649
|
-
# 父类的运行程序,相当于原生支持
|
|
650
|
-
super().run()
|
|
651
|
-
except:
|
|
652
|
-
self.logger.info(traceback.format_exc())
|
|
653
|
-
else:
|
|
654
|
-
raise Exception("运行模式错误 请检查 default or super")
|
|
655
|
-
|
|
656
|
-
def run_arg(self):
|
|
657
|
-
try:
|
|
658
|
-
if self.target:
|
|
659
|
-
self.threadval.set_result_queue(self.result_queue)
|
|
660
|
-
self.threadval.set_work_queue(self.work_queue)
|
|
661
|
-
self.target(self.threadval, *self.args, **self.kwargs)
|
|
662
|
-
finally:
|
|
663
|
-
del self.target, self.args, self.kwargs
|
|
664
|
-
|
|
665
|
-
def run_default(self):
|
|
666
|
-
"""
|
|
667
|
-
启动线程,默认的运行程序,
|
|
668
|
-
:return:
|
|
669
|
-
"""
|
|
670
|
-
while True:
|
|
671
|
-
try:
|
|
672
|
-
if self.thread_delete and self.threadval.thread_delete:
|
|
673
|
-
print("主动停止线程{},因为两个信号量都为True".format(self.getName()))
|
|
674
|
-
break
|
|
675
|
-
# 该标志标识着是否取得队列值并开始工作
|
|
676
|
-
self.runstatus = False
|
|
677
|
-
target, result_queue, args, kwargs = self.work_queue.get()
|
|
678
|
-
self.runstatus = True # 代表取到工作队列的值
|
|
679
|
-
# 更新字典 如果键相同 以初始化线程的键的值有效 所以尽量不要与初始化字典冲突
|
|
680
|
-
kwargs.update(self.kwargs)
|
|
681
|
-
# 初始化线程的元组参数拼接在后
|
|
682
|
-
args = args + self.args
|
|
683
|
-
#
|
|
684
|
-
self.threadval.set_result_queue(result_queue)
|
|
685
|
-
self.threadval.set_work_queue(self.work_queue)
|
|
686
|
-
target(self.threadval, *args, **kwargs)
|
|
687
|
-
self.work_queue.task_done()
|
|
688
|
-
except UnicodeDecodeError as e:
|
|
689
|
-
self.logger.error(traceback.format_exc())
|
|
690
|
-
except SystemExit as e:
|
|
691
|
-
if e.args == (-1,):
|
|
692
|
-
self.logger.error("由逻辑判断主动退出当前线程")
|
|
693
|
-
break
|
|
694
|
-
else:
|
|
695
|
-
self.logger.error("其他SystemExit错误,检查逻辑")
|
|
1
|
+
import ctypes
|
|
2
|
+
import functools
|
|
3
|
+
import inspect
|
|
4
|
+
import sys
|
|
5
|
+
import threading
|
|
6
|
+
# 创建一个有4个线程的线程池
|
|
7
|
+
import time
|
|
8
|
+
import traceback
|
|
9
|
+
from threading import Thread
|
|
10
|
+
|
|
11
|
+
from re_common.baselibrary.utils.basequeue import BaseQueue
|
|
12
|
+
from re_common.facade.loggerfacade import get_streamlogger
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ThreadInfo(object):
|
|
16
|
+
"""
|
|
17
|
+
该类存储着线程的信息,原本使用一个空的字典进行存储,
|
|
18
|
+
但字典的结构不可见且不清晰,故使用类进行结构化展示
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self):
|
|
22
|
+
self.is_restart = True
|
|
23
|
+
|
|
24
|
+
def set_thread(self, thread):
|
|
25
|
+
self.thread = thread
|
|
26
|
+
return self
|
|
27
|
+
|
|
28
|
+
def get_thread(self):
|
|
29
|
+
return self.thread
|
|
30
|
+
|
|
31
|
+
def set_thread_name(self, thread_name):
|
|
32
|
+
self.thread_name = thread_name
|
|
33
|
+
return self
|
|
34
|
+
|
|
35
|
+
def get_thread_name(self):
|
|
36
|
+
return self.thread_name
|
|
37
|
+
|
|
38
|
+
def set_kwargs(self, kwargs):
|
|
39
|
+
self.kwargs = kwargs
|
|
40
|
+
return self
|
|
41
|
+
|
|
42
|
+
def get_kwargs(self):
|
|
43
|
+
return self.kwargs
|
|
44
|
+
|
|
45
|
+
def set_args(self, args):
|
|
46
|
+
self.args = args
|
|
47
|
+
return self
|
|
48
|
+
|
|
49
|
+
def get_args(self):
|
|
50
|
+
return self.args
|
|
51
|
+
|
|
52
|
+
def set_dicts(self, dicts):
|
|
53
|
+
self.dicts = dicts
|
|
54
|
+
return self
|
|
55
|
+
|
|
56
|
+
def get_dicts(self):
|
|
57
|
+
return self.dicts
|
|
58
|
+
|
|
59
|
+
def set_is_restart(self, is_restart: bool):
|
|
60
|
+
"""
|
|
61
|
+
设置该线程是否应该重启
|
|
62
|
+
:param is_restart:
|
|
63
|
+
:return:
|
|
64
|
+
"""
|
|
65
|
+
self.is_restart = is_restart
|
|
66
|
+
return self
|
|
67
|
+
|
|
68
|
+
def get_is_restart(self):
|
|
69
|
+
return self.is_restart
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class ThreadPoolManger(object):
|
|
73
|
+
"""
|
|
74
|
+
线程池管理器
|
|
75
|
+
"""
|
|
76
|
+
# 线程锁
|
|
77
|
+
lock = threading.Lock()
|
|
78
|
+
|
|
79
|
+
def __init__(self, thread_num, logger=None):
|
|
80
|
+
if logger:
|
|
81
|
+
self.logger = logger
|
|
82
|
+
else:
|
|
83
|
+
self.logger = get_streamlogger()
|
|
84
|
+
self.prefix = "my_threading_task_"
|
|
85
|
+
# 任务队列
|
|
86
|
+
self.work_queue = BaseQueue(100)
|
|
87
|
+
# 结果队列 有时候结果需要在主线程处理或单独线程处理时使用
|
|
88
|
+
self.result_queue = BaseQueue(100)
|
|
89
|
+
# 线程队列 主要管线程间的通信
|
|
90
|
+
self.thread_queue = BaseQueue(10)
|
|
91
|
+
# 线程池 里面保存着线程对象
|
|
92
|
+
# self.threadpool = list()
|
|
93
|
+
# # 线程名列表
|
|
94
|
+
# self.initThreadsName = set()
|
|
95
|
+
# 应该赋予一个方法 用于回调
|
|
96
|
+
self.callback = None
|
|
97
|
+
# 线程池的字典 有时候需要在线程池中维护一些数据,所以没有采用原来的只维护线程对象
|
|
98
|
+
self.thread_pool_dicts = {}
|
|
99
|
+
|
|
100
|
+
# 线程数量 反馈当前工作线程数量
|
|
101
|
+
self.thread_num = thread_num
|
|
102
|
+
# 工作线程定量 该变量是为了维持线程的数量一定
|
|
103
|
+
self.max_workers = thread_num
|
|
104
|
+
# 是否是动态最大值
|
|
105
|
+
self.is_static_max = True
|
|
106
|
+
# 线程的参数 定义线程时使用
|
|
107
|
+
self.args = ()
|
|
108
|
+
self.kwargs = {}
|
|
109
|
+
|
|
110
|
+
# # 各种非工作线程池
|
|
111
|
+
# self.especial_thread_pool = list()
|
|
112
|
+
# # 特殊线程名
|
|
113
|
+
# self.especial_threads_Name = set()
|
|
114
|
+
|
|
115
|
+
# 各种非工作线程池 特殊线程名
|
|
116
|
+
self.especial_thread_pool_dicts = {}
|
|
117
|
+
|
|
118
|
+
# 该标志将用于sql间的同步 现在发现一个问题 在 线程中执行select会出现
|
|
119
|
+
# Command Out of Sync 错误 所以启用这个信号
|
|
120
|
+
# 这个错误表示 对于同一个连接 在不同线程中当一个线程发出sql且没有返回结果期间,
|
|
121
|
+
# 另一个线程页发出了请求,这时mysql的第一个请求在结果缓存中还没有返回 会冲突报错
|
|
122
|
+
# 这里主要是设置任务和处理结果用到同一个连接导致
|
|
123
|
+
self.event = threading.Event()
|
|
124
|
+
self.event_set()
|
|
125
|
+
# 独立的线程变量,很多时候 多线程变量是共享且线程不安全的,
|
|
126
|
+
# 该变量保证了线程内变量的安全与threadVal的概念相同
|
|
127
|
+
self.localVal = threading.local()
|
|
128
|
+
|
|
129
|
+
# # 初始化线程到线程池
|
|
130
|
+
self.__init_threading_pool(self.thread_num)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def thread_lock(cls, func):
|
|
134
|
+
@functools.wraps(func)
|
|
135
|
+
def wrapper(*args, **kwargs):
|
|
136
|
+
try:
|
|
137
|
+
cls.lock.acquire()
|
|
138
|
+
return func(*args, **kwargs)
|
|
139
|
+
finally:
|
|
140
|
+
cls.lock.release()
|
|
141
|
+
|
|
142
|
+
return wrapper
|
|
143
|
+
|
|
144
|
+
def set_args(self, args):
|
|
145
|
+
"""
|
|
146
|
+
设置元组参数
|
|
147
|
+
:param args:
|
|
148
|
+
:return:
|
|
149
|
+
"""
|
|
150
|
+
self.args = args
|
|
151
|
+
|
|
152
|
+
def set_kwargs(self, kwargs):
|
|
153
|
+
"""
|
|
154
|
+
设置字典参数
|
|
155
|
+
:param kwargs:
|
|
156
|
+
:return:
|
|
157
|
+
"""
|
|
158
|
+
self.kwargs = kwargs
|
|
159
|
+
|
|
160
|
+
def set_is_static_max(self, is_static_max):
|
|
161
|
+
"""
|
|
162
|
+
设置是否允许
|
|
163
|
+
:param is_static_max:
|
|
164
|
+
:return:
|
|
165
|
+
"""
|
|
166
|
+
self.is_static_max = is_static_max
|
|
167
|
+
|
|
168
|
+
def set_max_workers(self, num):
|
|
169
|
+
"""
|
|
170
|
+
如果线程数是动态的,就允许设置大小
|
|
171
|
+
:param num:
|
|
172
|
+
:return:
|
|
173
|
+
"""
|
|
174
|
+
if self.is_static_max:
|
|
175
|
+
self.logger.info("是静态最大线程数,不能对最大线程数进行设置")
|
|
176
|
+
else:
|
|
177
|
+
self.max_workers = num
|
|
178
|
+
|
|
179
|
+
def get_max_workers(self):
|
|
180
|
+
return self.max_workers
|
|
181
|
+
|
|
182
|
+
def get_localVal(self):
|
|
183
|
+
"""
|
|
184
|
+
获取线程独立变量
|
|
185
|
+
:return:
|
|
186
|
+
"""
|
|
187
|
+
return self.localVal
|
|
188
|
+
|
|
189
|
+
def set_localVal(self, val):
|
|
190
|
+
self.localVal = val
|
|
191
|
+
|
|
192
|
+
def set_callback(self, callback):
|
|
193
|
+
self.callback = callback
|
|
194
|
+
|
|
195
|
+
def event_set(self):
|
|
196
|
+
"""
|
|
197
|
+
设置event 允许wait继续运行 状态为True
|
|
198
|
+
:return:
|
|
199
|
+
"""
|
|
200
|
+
self.event.set()
|
|
201
|
+
|
|
202
|
+
def event_clear(self):
|
|
203
|
+
"""
|
|
204
|
+
设置值为False 不允许运行其他线程
|
|
205
|
+
:return:
|
|
206
|
+
"""
|
|
207
|
+
self.event.clear()
|
|
208
|
+
|
|
209
|
+
def event_is_set(self):
|
|
210
|
+
"""
|
|
211
|
+
返回标志
|
|
212
|
+
:return:
|
|
213
|
+
"""
|
|
214
|
+
return self.event.is_set()
|
|
215
|
+
|
|
216
|
+
def event_wait(self, timeout=None):
|
|
217
|
+
self.event.wait(timeout)
|
|
218
|
+
|
|
219
|
+
def set_thread_name_prefix(self, prefix):
|
|
220
|
+
self.prefix = prefix
|
|
221
|
+
|
|
222
|
+
def __init_threading_pool(self, thread_num):
|
|
223
|
+
"""
|
|
224
|
+
初始化线程池,创建指定数量的线程池
|
|
225
|
+
:param thread_num:
|
|
226
|
+
:return:
|
|
227
|
+
"""
|
|
228
|
+
self.logger.info("初始化工作线程数量为:%d" % thread_num)
|
|
229
|
+
for i in range(int(thread_num)):
|
|
230
|
+
# 新建一个线程
|
|
231
|
+
thread = ThreadManager(self.work_queue,
|
|
232
|
+
self.result_queue,
|
|
233
|
+
self.thread_queue,
|
|
234
|
+
self.logger,
|
|
235
|
+
args=self.args,
|
|
236
|
+
kwargs=self.kwargs)
|
|
237
|
+
# 线程名
|
|
238
|
+
threadName = "{}{}".format(self.prefix, i + 1)
|
|
239
|
+
if threadName in self.thread_pool_dicts:
|
|
240
|
+
self.logger.warn("线程名%s在线程池中已经存在,跳过" % threadName)
|
|
241
|
+
else:
|
|
242
|
+
# 设置线程名
|
|
243
|
+
thread.setName(threadName)
|
|
244
|
+
self.set_thread_pool_dicts(self.thread_pool_dicts, threadName, thread, self.args, self.kwargs)
|
|
245
|
+
|
|
246
|
+
def set_thread_pool_dicts(self, thread_pool_dicts, threadName, thread, args, kwargs):
|
|
247
|
+
"""
|
|
248
|
+
这里调用了一个钩子函数 可以在dicts中加入其他参数
|
|
249
|
+
:param thread_pool_dicts: 线程池字典对象
|
|
250
|
+
:param threadName: 线程名
|
|
251
|
+
:param thread: 线程
|
|
252
|
+
:param args:
|
|
253
|
+
:param kwargs:
|
|
254
|
+
:return:
|
|
255
|
+
"""
|
|
256
|
+
threadinfo = ThreadInfo()
|
|
257
|
+
threadinfo.set_thread(thread)
|
|
258
|
+
threadinfo.set_kwargs(kwargs)
|
|
259
|
+
threadinfo.set_args(args)
|
|
260
|
+
threadinfo.set_thread_name(threadName)
|
|
261
|
+
if self.callback:
|
|
262
|
+
# 对象使用
|
|
263
|
+
dicts = self.callback(threadinfo)
|
|
264
|
+
else:
|
|
265
|
+
# 继承时使用
|
|
266
|
+
dicts = self.thread_pool_hook(threadinfo)
|
|
267
|
+
if not dicts:
|
|
268
|
+
dicts = {}
|
|
269
|
+
threadinfo.set_dicts(dicts)
|
|
270
|
+
thread_pool_dicts[threadName] = threadinfo
|
|
271
|
+
|
|
272
|
+
def thread_pool_hook(self, threadinfo: ThreadInfo) -> dict:
|
|
273
|
+
"""
|
|
274
|
+
钩子函数 可以被重写
|
|
275
|
+
主要重写里面的dicts部分
|
|
276
|
+
:return:
|
|
277
|
+
"""
|
|
278
|
+
return {}
|
|
279
|
+
|
|
280
|
+
def reload_thread(self, thread_name):
|
|
281
|
+
"""
|
|
282
|
+
通过线程名重启线程
|
|
283
|
+
:param thread_name:
|
|
284
|
+
:return:
|
|
285
|
+
"""
|
|
286
|
+
is_start = False
|
|
287
|
+
if thread_name in self.thread_pool_dicts:
|
|
288
|
+
self.logger.info("{}线程名存在".format(thread_name))
|
|
289
|
+
if self.thread_pool_dicts[thread_name].get_thread().is_alive():
|
|
290
|
+
self.logger.info("{}线程名是存活的".format(thread_name))
|
|
291
|
+
is_start = True
|
|
292
|
+
else:
|
|
293
|
+
self.logger.info("{}线程名是没有存活 需要重启".format(thread_name))
|
|
294
|
+
|
|
295
|
+
if not is_start:
|
|
296
|
+
args = self.thread_pool_dicts[thread_name].get_args()
|
|
297
|
+
kwargs = self.thread_pool_dicts[thread_name].get_kwargs()
|
|
298
|
+
self.logger.info("新建或重启线程{}".format(thread_name))
|
|
299
|
+
# 新建一个线程
|
|
300
|
+
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue, self.logger, args=args,
|
|
301
|
+
kwargs=kwargs)
|
|
302
|
+
# 设置线程名
|
|
303
|
+
thread.setName(thread_name)
|
|
304
|
+
# # 加入线程池
|
|
305
|
+
# self.threadpool.append(thread)
|
|
306
|
+
self.set_thread_pool_dicts(self.thread_pool_dicts, thread_name, thread, args, kwargs)
|
|
307
|
+
thread.start()
|
|
308
|
+
|
|
309
|
+
def add_thread(self, thread_num):
|
|
310
|
+
"""
|
|
311
|
+
添加线程,thread_num是添加线程的数量
|
|
312
|
+
:param thread_num:
|
|
313
|
+
:return:
|
|
314
|
+
"""
|
|
315
|
+
# 判断可开线程的数量
|
|
316
|
+
if self.thread_num < self.max_workers:
|
|
317
|
+
if self.max_workers - self.thread_num < thread_num:
|
|
318
|
+
thread_num = self.max_workers - self.thread_num
|
|
319
|
+
else:
|
|
320
|
+
self.logger.info("线程已达到最大量,不能再新开线程")
|
|
321
|
+
return False
|
|
322
|
+
# 添加新的线程
|
|
323
|
+
count = 0
|
|
324
|
+
num = 0
|
|
325
|
+
while thread_num > count:
|
|
326
|
+
num += 1
|
|
327
|
+
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue,
|
|
328
|
+
self.logger,
|
|
329
|
+
args=self.args,
|
|
330
|
+
kwargs=self.kwargs)
|
|
331
|
+
thread_name = "{}{}".format(self.prefix, num)
|
|
332
|
+
if thread_name in self.thread_pool_dicts:
|
|
333
|
+
continue
|
|
334
|
+
thread.setName(thread_name)
|
|
335
|
+
self.logger.info("添加一个线程{}".format(thread_name))
|
|
336
|
+
self.set_thread_pool_dicts(self.thread_pool_dicts, thread_name, thread, self.args, self.kwargs)
|
|
337
|
+
count += 1
|
|
338
|
+
self.get_thread_num()
|
|
339
|
+
return True
|
|
340
|
+
|
|
341
|
+
def delete_thread(self, thread_num):
|
|
342
|
+
"""
|
|
343
|
+
删除多少个线程,thread_num为删除数量
|
|
344
|
+
:param thread_num:
|
|
345
|
+
:return:
|
|
346
|
+
"""
|
|
347
|
+
try:
|
|
348
|
+
i = 0
|
|
349
|
+
for key in list(self.thread_pool_dicts.keys()):
|
|
350
|
+
thread = self.thread_pool_dicts[key].get_thread()
|
|
351
|
+
if not thread.runstatus:
|
|
352
|
+
# 优先删除处于等待任务的线程
|
|
353
|
+
thread.thread_delete = True
|
|
354
|
+
self.stop_thread(thread)
|
|
355
|
+
del self.thread_pool_dicts[key]
|
|
356
|
+
i += 1
|
|
357
|
+
elif thread.threadval.thread_delete:
|
|
358
|
+
# 删除该线程 表示线程池想删除(删除逻辑为我想删除 且程序内部允许删除时删除)
|
|
359
|
+
thread.thread_delete = True
|
|
360
|
+
del self.thread_pool_dicts[key]
|
|
361
|
+
i += 1
|
|
362
|
+
if i >= thread_num:
|
|
363
|
+
break
|
|
364
|
+
except IndexError:
|
|
365
|
+
pass
|
|
366
|
+
self.get_thread_num()
|
|
367
|
+
|
|
368
|
+
def get_thread_num(self):
|
|
369
|
+
self.thread_num = len(self.thread_pool_dicts)
|
|
370
|
+
return self.thread_num
|
|
371
|
+
|
|
372
|
+
def set_thread_num(self, thread_num):
|
|
373
|
+
"""
|
|
374
|
+
设置当前线程数量 改设置保证了线程数量 多的会被删除,少的会被添加
|
|
375
|
+
:return:
|
|
376
|
+
"""
|
|
377
|
+
if thread_num > self.get_thread_num():
|
|
378
|
+
self.add_thread(thread_num - self.thread_num)
|
|
379
|
+
else:
|
|
380
|
+
self.delete_thread(self.get_thread_num() - thread_num)
|
|
381
|
+
# self.threadpool = self.threadpool[:int(thread_num)]
|
|
382
|
+
self.thread_num = thread_num
|
|
383
|
+
|
|
384
|
+
def add_super_thread(self, func, thread_name, mode="super", *args, **kwargs):
|
|
385
|
+
"""
|
|
386
|
+
添加一个线程,该线程直接由原生线程控制,
|
|
387
|
+
:param func:
|
|
388
|
+
:param thread_name:
|
|
389
|
+
:param args:
|
|
390
|
+
:param kwargs:
|
|
391
|
+
:return:
|
|
392
|
+
"""
|
|
393
|
+
thread = ThreadManager(self.work_queue, self.result_queue, self.thread_queue,
|
|
394
|
+
self.logger,
|
|
395
|
+
target=func, name=thread_name,
|
|
396
|
+
args=args,
|
|
397
|
+
kwargs=kwargs)
|
|
398
|
+
thread.set_mode(mode)
|
|
399
|
+
return thread
|
|
400
|
+
|
|
401
|
+
def set_add_especial_thread(self, func, threadname, mode="super", *args, **kwargs):
|
|
402
|
+
"""
|
|
403
|
+
添加特殊的线程
|
|
404
|
+
:return:
|
|
405
|
+
"""
|
|
406
|
+
# 得到一个线程对象
|
|
407
|
+
thread = self.add_super_thread(func, threadname, mode, *args, **kwargs)
|
|
408
|
+
self.set_thread_pool_dicts(self.especial_thread_pool_dicts, threadname, thread, args, kwargs)
|
|
409
|
+
return thread
|
|
410
|
+
|
|
411
|
+
def add_job(self, func, *args, **kwargs):
|
|
412
|
+
"""
|
|
413
|
+
将任务放入队列,等待线程池阻塞读取,参数是被执行的函数和函数的参数
|
|
414
|
+
:param func:
|
|
415
|
+
:param args:
|
|
416
|
+
:param kwargs:
|
|
417
|
+
:return:
|
|
418
|
+
"""
|
|
419
|
+
self.work_queue.put((func, self.result_queue, args, kwargs))
|
|
420
|
+
|
|
421
|
+
def start(self):
|
|
422
|
+
for thread in self.thread_pool_dicts:
|
|
423
|
+
time.sleep(2)
|
|
424
|
+
if self.thread_pool_dicts[thread]:
|
|
425
|
+
thread = self.thread_pool_dicts[thread].get_thread()
|
|
426
|
+
if thread and not thread.is_alive():
|
|
427
|
+
thread.start()
|
|
428
|
+
|
|
429
|
+
def especial_start(self):
|
|
430
|
+
for threadname in self.especial_thread_pool_dicts:
|
|
431
|
+
if self.especial_thread_pool_dicts[threadname]:
|
|
432
|
+
threadinfo = self.especial_thread_pool_dicts[threadname]
|
|
433
|
+
thread = threadinfo.thread
|
|
434
|
+
if thread and not thread.is_alive():
|
|
435
|
+
self.logger.info("启动线程{}".format(thread.getName()))
|
|
436
|
+
thread.start()
|
|
437
|
+
else:
|
|
438
|
+
self.logger.info("启动线程{} 失败".format(thread.getName()))
|
|
439
|
+
|
|
440
|
+
def get_now_thread(self):
|
|
441
|
+
"""
|
|
442
|
+
获取进程中还存在的线程
|
|
443
|
+
:return:
|
|
444
|
+
"""
|
|
445
|
+
# 用来保存当前线程名称
|
|
446
|
+
nowThreadsName = []
|
|
447
|
+
# 获取当前线程名
|
|
448
|
+
now = threading.enumerate()
|
|
449
|
+
for i in now:
|
|
450
|
+
# 保存当前线程名称
|
|
451
|
+
nowThreadsName.append(i.getName())
|
|
452
|
+
return nowThreadsName
|
|
453
|
+
|
|
454
|
+
# 防止线程意外挂掉 挂掉线程重启
|
|
455
|
+
def checkThread(self):
|
|
456
|
+
nowThreadsName = self.get_now_thread()
|
|
457
|
+
# 循环线程池的key
|
|
458
|
+
for name in list(self.thread_pool_dicts.keys()):
|
|
459
|
+
# 取出线程对象
|
|
460
|
+
thread = self.thread_pool_dicts[name].get_thread()
|
|
461
|
+
# 如果线程字典为空 代表已被删除
|
|
462
|
+
if name in nowThreadsName and thread.is_alive():
|
|
463
|
+
pass # 当前某线程名包含在初始化线程组中,可以认为线程仍在运行
|
|
464
|
+
else:
|
|
465
|
+
self.reload_thread(name) # 重启线程
|
|
466
|
+
# 如果不是静态最大值 线程可以波动
|
|
467
|
+
if not self.is_static_max:
|
|
468
|
+
# 空闲线程
|
|
469
|
+
free_thread = 0
|
|
470
|
+
# 判断线程空闲情况
|
|
471
|
+
for name in list(self.thread_pool_dicts.keys()):
|
|
472
|
+
thread = self.thread_pool_dicts[name].get_thread()
|
|
473
|
+
if not thread.runstatus:
|
|
474
|
+
# 代表该线程等待工作队列,列入空闲线程
|
|
475
|
+
free_thread += 1
|
|
476
|
+
elif thread.threadval.thread_delete:
|
|
477
|
+
free_thread += 1
|
|
478
|
+
|
|
479
|
+
# 允许冗余2个工作线程 避免在零界点不停的创建,删除
|
|
480
|
+
if free_thread > 2:
|
|
481
|
+
self.max_workers = self.max_workers - (free_thread - 2)
|
|
482
|
+
|
|
483
|
+
# 判断是否需要删除线程
|
|
484
|
+
if len(self.thread_pool_dicts) > self.max_workers:
|
|
485
|
+
self.logger.info("线程池有{},最大线程数量{},调用删除线程程序".format(len(self.thread_pool_dicts), self.max_workers))
|
|
486
|
+
self.delete_thread(len(self.thread_pool_dicts) - self.max_workers)
|
|
487
|
+
|
|
488
|
+
self.logger.info("当前线程数量为{},线程为:{}".format(len(self.thread_pool_dicts), list(self.thread_pool_dicts.keys())))
|
|
489
|
+
|
|
490
|
+
def checkThreadRunFinish(self):
|
|
491
|
+
"""
|
|
492
|
+
通过等待的方式判断结束,等待是因为任务队列取出任务后在运行,还没放入结果队列
|
|
493
|
+
:return:
|
|
494
|
+
"""
|
|
495
|
+
self.logger.info("result_queue is empty:{}".format(self.result_queue.is_empty()))
|
|
496
|
+
self.logger.info("work_queue is empty:{}".format(self.work_queue.is_empty()))
|
|
497
|
+
if self.result_queue.is_empty() and self.work_queue.is_empty():
|
|
498
|
+
time.sleep(10)
|
|
499
|
+
t1 = self.result_queue.is_empty()
|
|
500
|
+
time.sleep(10)
|
|
501
|
+
t2 = self.result_queue.is_empty()
|
|
502
|
+
if t1 and t2:
|
|
503
|
+
if self.work_queue.is_empty():
|
|
504
|
+
return True
|
|
505
|
+
return False
|
|
506
|
+
return False
|
|
507
|
+
|
|
508
|
+
# 下面两个方法是强制退出线程的方法
|
|
509
|
+
def _async_raise(self, tid, exctype):
|
|
510
|
+
"""raises the exception, performs cleanup if needed"""
|
|
511
|
+
tid = ctypes.c_long(tid)
|
|
512
|
+
if not inspect.isclass(exctype):
|
|
513
|
+
exctype = type(exctype)
|
|
514
|
+
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
|
|
515
|
+
if res == 0:
|
|
516
|
+
raise ValueError("invalid thread id")
|
|
517
|
+
elif res != 1:
|
|
518
|
+
# """if it returns a number greater than one, you're in trouble,
|
|
519
|
+
# and you should call it again with exc=NULL to revert the effect"""
|
|
520
|
+
ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
|
|
521
|
+
raise SystemError("PyThreadState_SetAsyncExc failed")
|
|
522
|
+
|
|
523
|
+
def stop_thread(self, thread):
|
|
524
|
+
if thread:
|
|
525
|
+
try:
|
|
526
|
+
self.logger.info("thread is {};thread.ident 的值为:{}".format(thread, thread.ident))
|
|
527
|
+
if thread.ident:
|
|
528
|
+
self._async_raise(thread.ident, SystemExit)
|
|
529
|
+
except ValueError as e:
|
|
530
|
+
self.logger.info("已经运行完毕 不需要删除了")
|
|
531
|
+
else:
|
|
532
|
+
self.logger.info("传入的线程对象为空,理论上不应该出现这种逻辑 结束程序检查逻辑")
|
|
533
|
+
sys.exit(-1)
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
class ThreadVal(object):
|
|
537
|
+
"""
|
|
538
|
+
该对象维护线程函数的变量以及与线程对象间的交互
|
|
539
|
+
"""
|
|
540
|
+
|
|
541
|
+
def __init__(self):
|
|
542
|
+
# 该线程是否被删除
|
|
543
|
+
self.thread_delete = False
|
|
544
|
+
# 线程初始化参数
|
|
545
|
+
self.args = ()
|
|
546
|
+
self.kwargs = None
|
|
547
|
+
self.result_queue = None
|
|
548
|
+
self.work_queue = None
|
|
549
|
+
|
|
550
|
+
def set_args(self, args):
|
|
551
|
+
self.args = args
|
|
552
|
+
|
|
553
|
+
def set_kwargs(self, kwargs):
|
|
554
|
+
self.kwargs = kwargs
|
|
555
|
+
|
|
556
|
+
def set_result_queue(self, result_queue):
|
|
557
|
+
self.result_queue = result_queue
|
|
558
|
+
|
|
559
|
+
def get_result_queue(self):
|
|
560
|
+
return self.result_queue
|
|
561
|
+
|
|
562
|
+
def set_work_queue(self, work_queue):
|
|
563
|
+
self.work_queue = work_queue
|
|
564
|
+
|
|
565
|
+
def get_work_queue(self):
|
|
566
|
+
return self.work_queue
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
class ThreadManager(Thread):
|
|
570
|
+
"""
|
|
571
|
+
定义线程类,继承threading.Thread
|
|
572
|
+
该类主要实现线程的运行
|
|
573
|
+
"""
|
|
574
|
+
|
|
575
|
+
def __init__(self, work_queue=None, result_queue=None, thread_queue=None, logger=None, group=None, target=None,
|
|
576
|
+
name=None, args=(), kwargs=None, daemon=True, mode="default"):
|
|
577
|
+
if mode == "default":
|
|
578
|
+
if work_queue is None or result_queue is None or thread_queue is None:
|
|
579
|
+
raise Exception("work_queue result_queue thread_queue 必须存在")
|
|
580
|
+
if args is None:
|
|
581
|
+
args = ()
|
|
582
|
+
# 线程本身的参数
|
|
583
|
+
Thread.__init__(self, group, target, name,
|
|
584
|
+
args, kwargs, daemon=daemon)
|
|
585
|
+
if kwargs is None:
|
|
586
|
+
kwargs = {}
|
|
587
|
+
if logger:
|
|
588
|
+
self.logger = logger
|
|
589
|
+
else:
|
|
590
|
+
self.logger = get_streamlogger()
|
|
591
|
+
self.target = target
|
|
592
|
+
self.kwargs = kwargs
|
|
593
|
+
self.args = args
|
|
594
|
+
# 接受两个队列 一个处理结果 一个发送任务
|
|
595
|
+
self.work_queue = work_queue
|
|
596
|
+
self.result_queue = result_queue
|
|
597
|
+
# 线程队列
|
|
598
|
+
self.thread_queue = thread_queue
|
|
599
|
+
# 主线程退出 该线程也会退出
|
|
600
|
+
self.daemon = daemon
|
|
601
|
+
# 一个标识 如果为False代表线程运行完毕等待新的任务到来,否则表示任务正在运行
|
|
602
|
+
# 这个标志是为了检查程序在运行中还是等待状态
|
|
603
|
+
self.runstatus = False
|
|
604
|
+
# 设置该标志是为了表示是否愿意被重新启动,因为有些线程只需要运行一次
|
|
605
|
+
# 而有的需要长期运行且有一定的重启机制(目前暂未启动该标志)
|
|
606
|
+
self.is_restart = True
|
|
607
|
+
# 为了兼容普通线程类模式 "default" 自己写的run 方法 "super": 父类的run方法
|
|
608
|
+
self.mode = mode
|
|
609
|
+
# 是否可以被删除 True 线程可以停止,False 不可以被停止 有时候我们需要删除一批线程 但是 线程不能中间
|
|
610
|
+
# 状态被删除 故需要设置该标志
|
|
611
|
+
self.thread_delete = False
|
|
612
|
+
# 线程内部的一个类对象 每个线程维护一个保证里面的数据线程安全,以后为每个线程提供服务
|
|
613
|
+
self.threadval = ThreadVal()
|
|
614
|
+
self.threadval.set_args(self.args)
|
|
615
|
+
self.threadval.set_kwargs(self.kwargs)
|
|
616
|
+
|
|
617
|
+
def get_runstatus(self):
|
|
618
|
+
return self.runstatus
|
|
619
|
+
|
|
620
|
+
def set_runstatus(self, runstatus):
|
|
621
|
+
self.runstatus = runstatus
|
|
622
|
+
|
|
623
|
+
def get_is_restart(self):
|
|
624
|
+
return self.is_restart
|
|
625
|
+
|
|
626
|
+
def set_is_restart(self, is_restart):
|
|
627
|
+
self.is_restart = is_restart
|
|
628
|
+
|
|
629
|
+
def set_mode(self, mode):
|
|
630
|
+
"""
|
|
631
|
+
设置运行模式 super or default
|
|
632
|
+
super 将方法直接传入target
|
|
633
|
+
default 使用自己封装的run
|
|
634
|
+
:param mode:
|
|
635
|
+
:return:
|
|
636
|
+
"""
|
|
637
|
+
self.mode = mode
|
|
638
|
+
|
|
639
|
+
def get_mode(self):
|
|
640
|
+
return self.mode
|
|
641
|
+
|
|
642
|
+
def run(self):
|
|
643
|
+
if self.mode == "default":
|
|
644
|
+
self.run_default()
|
|
645
|
+
elif self.mode == "mysuper":
|
|
646
|
+
self.run_arg()
|
|
647
|
+
elif self.mode == "super":
|
|
648
|
+
try:
|
|
649
|
+
# 父类的运行程序,相当于原生支持
|
|
650
|
+
super().run()
|
|
651
|
+
except:
|
|
652
|
+
self.logger.info(traceback.format_exc())
|
|
653
|
+
else:
|
|
654
|
+
raise Exception("运行模式错误 请检查 default or super")
|
|
655
|
+
|
|
656
|
+
def run_arg(self):
|
|
657
|
+
try:
|
|
658
|
+
if self.target:
|
|
659
|
+
self.threadval.set_result_queue(self.result_queue)
|
|
660
|
+
self.threadval.set_work_queue(self.work_queue)
|
|
661
|
+
self.target(self.threadval, *self.args, **self.kwargs)
|
|
662
|
+
finally:
|
|
663
|
+
del self.target, self.args, self.kwargs
|
|
664
|
+
|
|
665
|
+
def run_default(self):
|
|
666
|
+
"""
|
|
667
|
+
启动线程,默认的运行程序,
|
|
668
|
+
:return:
|
|
669
|
+
"""
|
|
670
|
+
while True:
|
|
671
|
+
try:
|
|
672
|
+
if self.thread_delete and self.threadval.thread_delete:
|
|
673
|
+
print("主动停止线程{},因为两个信号量都为True".format(self.getName()))
|
|
674
|
+
break
|
|
675
|
+
# 该标志标识着是否取得队列值并开始工作
|
|
676
|
+
self.runstatus = False
|
|
677
|
+
target, result_queue, args, kwargs = self.work_queue.get()
|
|
678
|
+
self.runstatus = True # 代表取到工作队列的值
|
|
679
|
+
# 更新字典 如果键相同 以初始化线程的键的值有效 所以尽量不要与初始化字典冲突
|
|
680
|
+
kwargs.update(self.kwargs)
|
|
681
|
+
# 初始化线程的元组参数拼接在后
|
|
682
|
+
args = args + self.args
|
|
683
|
+
#
|
|
684
|
+
self.threadval.set_result_queue(result_queue)
|
|
685
|
+
self.threadval.set_work_queue(self.work_queue)
|
|
686
|
+
target(self.threadval, *args, **kwargs)
|
|
687
|
+
self.work_queue.task_done()
|
|
688
|
+
except UnicodeDecodeError as e:
|
|
689
|
+
self.logger.error(traceback.format_exc())
|
|
690
|
+
except SystemExit as e:
|
|
691
|
+
if e.args == (-1,):
|
|
692
|
+
self.logger.error("由逻辑判断主动退出当前线程")
|
|
693
|
+
break
|
|
694
|
+
else:
|
|
695
|
+
self.logger.error("其他SystemExit错误,检查逻辑")
|