re-common 10.0.39__py3-none-any.whl → 10.0.41__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.
Files changed (221) hide show
  1. re_common/baselibrary/__init__.py +4 -4
  2. re_common/baselibrary/baseabs/__init__.py +6 -6
  3. re_common/baselibrary/baseabs/baseabs.py +26 -26
  4. re_common/baselibrary/database/mbuilder.py +132 -132
  5. re_common/baselibrary/database/moudle.py +93 -93
  6. re_common/baselibrary/database/msqlite3.py +194 -194
  7. re_common/baselibrary/database/mysql.py +169 -169
  8. re_common/baselibrary/database/sql_factory.py +26 -26
  9. re_common/baselibrary/mthread/MThreadingRun.py +486 -486
  10. re_common/baselibrary/mthread/MThreadingRunEvent.py +349 -349
  11. re_common/baselibrary/mthread/__init__.py +2 -2
  12. re_common/baselibrary/mthread/mythreading.py +695 -695
  13. re_common/baselibrary/pakge_other/socks.py +404 -404
  14. re_common/baselibrary/readconfig/config_factory.py +18 -18
  15. re_common/baselibrary/readconfig/ini_config.py +317 -317
  16. re_common/baselibrary/readconfig/toml_config.py +49 -49
  17. re_common/baselibrary/temporary/envdata.py +36 -36
  18. re_common/baselibrary/tools/all_requests/aiohttp_request.py +118 -118
  19. re_common/baselibrary/tools/all_requests/httpx_requet.py +102 -102
  20. re_common/baselibrary/tools/all_requests/mrequest.py +412 -412
  21. re_common/baselibrary/tools/all_requests/requests_request.py +81 -81
  22. re_common/baselibrary/tools/batch_compre/bijiao_batch.py +31 -31
  23. re_common/baselibrary/tools/contrast_db3.py +123 -123
  24. re_common/baselibrary/tools/copy_file.py +39 -39
  25. re_common/baselibrary/tools/db3_2_sizedb3.py +102 -102
  26. re_common/baselibrary/tools/foreachgz.py +39 -39
  27. re_common/baselibrary/tools/get_attr.py +10 -10
  28. re_common/baselibrary/tools/image_to_pdf.py +61 -61
  29. re_common/baselibrary/tools/java_code_deal.py +139 -139
  30. re_common/baselibrary/tools/javacode.py +79 -79
  31. re_common/baselibrary/tools/mdb_db3.py +48 -48
  32. re_common/baselibrary/tools/merge_file.py +171 -171
  33. re_common/baselibrary/tools/merge_gz_file.py +165 -165
  34. re_common/baselibrary/tools/mhdfstools/down_hdfs_files.py +42 -42
  35. re_common/baselibrary/tools/mhdfstools/hdfst.py +42 -42
  36. re_common/baselibrary/tools/mhdfstools/up_hdfs_files.py +38 -38
  37. re_common/baselibrary/tools/mongo_tools.py +50 -50
  38. re_common/baselibrary/tools/move_file.py +170 -170
  39. re_common/baselibrary/tools/move_mongo/mongo_table_to_file.py +63 -63
  40. re_common/baselibrary/tools/move_mongo/move_mongo_table.py +354 -354
  41. re_common/baselibrary/tools/move_mongo/use_mttf.py +18 -18
  42. re_common/baselibrary/tools/move_mongo/use_mv.py +93 -93
  43. re_common/baselibrary/tools/mpandas/mpandasreadexcel.py +125 -125
  44. re_common/baselibrary/tools/mpandas/pandas_visualization.py +7 -7
  45. re_common/baselibrary/tools/myparsel.py +104 -104
  46. re_common/baselibrary/tools/rename_dir_file.py +37 -37
  47. re_common/baselibrary/tools/sequoiadb_utils.py +398 -398
  48. re_common/baselibrary/tools/split_line_to_many.py +25 -25
  49. re_common/baselibrary/tools/stringtodicts.py +33 -33
  50. re_common/baselibrary/tools/workwechant_bot.py +84 -84
  51. re_common/baselibrary/utils/baseaiohttp.py +296 -296
  52. re_common/baselibrary/utils/baseaiomysql.py +87 -87
  53. re_common/baselibrary/utils/baseallstep.py +191 -191
  54. re_common/baselibrary/utils/baseavro.py +19 -19
  55. re_common/baselibrary/utils/baseboto3.py +291 -291
  56. re_common/baselibrary/utils/basecsv.py +32 -32
  57. re_common/baselibrary/utils/basedict.py +133 -133
  58. re_common/baselibrary/utils/basedir.py +241 -241
  59. re_common/baselibrary/utils/baseencode.py +351 -351
  60. re_common/baselibrary/utils/baseencoding.py +28 -28
  61. re_common/baselibrary/utils/baseesdsl.py +86 -86
  62. re_common/baselibrary/utils/baseexcel.py +264 -264
  63. re_common/baselibrary/utils/baseexcept.py +109 -109
  64. re_common/baselibrary/utils/basefile.py +654 -654
  65. re_common/baselibrary/utils/baseftp.py +214 -214
  66. re_common/baselibrary/utils/basegzip.py +60 -60
  67. re_common/baselibrary/utils/basehdfs.py +135 -135
  68. re_common/baselibrary/utils/basehttpx.py +268 -268
  69. re_common/baselibrary/utils/baseip.py +87 -87
  70. re_common/baselibrary/utils/basejson.py +2 -2
  71. re_common/baselibrary/utils/baselist.py +32 -32
  72. re_common/baselibrary/utils/basemotor.py +190 -190
  73. re_common/baselibrary/utils/basemssql.py +98 -98
  74. re_common/baselibrary/utils/baseodbc.py +113 -113
  75. re_common/baselibrary/utils/basepandas.py +302 -302
  76. re_common/baselibrary/utils/basepeewee.py +11 -11
  77. re_common/baselibrary/utils/basepika.py +180 -180
  78. re_common/baselibrary/utils/basepydash.py +143 -143
  79. re_common/baselibrary/utils/basepymongo.py +230 -230
  80. re_common/baselibrary/utils/basequeue.py +22 -22
  81. re_common/baselibrary/utils/baserar.py +57 -57
  82. re_common/baselibrary/utils/baserequest.py +279 -279
  83. re_common/baselibrary/utils/baseset.py +8 -8
  84. re_common/baselibrary/utils/basesmb.py +403 -403
  85. re_common/baselibrary/utils/basestring.py +382 -382
  86. re_common/baselibrary/utils/basetime.py +320 -320
  87. re_common/baselibrary/utils/baseurl.py +121 -121
  88. re_common/baselibrary/utils/basezip.py +57 -57
  89. re_common/baselibrary/utils/core/__init__.py +7 -7
  90. re_common/baselibrary/utils/core/bottomutils.py +18 -18
  91. re_common/baselibrary/utils/core/mdeprecated.py +327 -327
  92. re_common/baselibrary/utils/core/mlamada.py +16 -16
  93. re_common/baselibrary/utils/core/msginfo.py +25 -25
  94. re_common/baselibrary/utils/core/requests_core.py +103 -103
  95. re_common/baselibrary/utils/fateadm.py +429 -429
  96. re_common/baselibrary/utils/importfun.py +123 -123
  97. re_common/baselibrary/utils/mfaker.py +57 -57
  98. re_common/baselibrary/utils/my_abc/__init__.py +3 -3
  99. re_common/baselibrary/utils/my_abc/better_abc.py +32 -32
  100. re_common/baselibrary/utils/mylogger.py +414 -414
  101. re_common/baselibrary/utils/myredisclient.py +861 -861
  102. re_common/baselibrary/utils/pipupgrade.py +21 -21
  103. re_common/baselibrary/utils/ringlist.py +85 -85
  104. re_common/baselibrary/utils/version_compare.py +36 -36
  105. re_common/baselibrary/utils/ydmhttp.py +126 -126
  106. re_common/facade/lazy_import.py +11 -11
  107. re_common/facade/loggerfacade.py +25 -25
  108. re_common/facade/mysqlfacade.py +467 -467
  109. re_common/facade/now.py +31 -31
  110. re_common/facade/sqlite3facade.py +257 -257
  111. re_common/facade/use/mq_use_facade.py +83 -83
  112. re_common/facade/use/proxy_use_facade.py +19 -19
  113. re_common/libtest/base_dict_test.py +19 -19
  114. re_common/libtest/baseavro_test.py +13 -13
  115. re_common/libtest/basefile_test.py +14 -14
  116. re_common/libtest/basemssql_test.py +77 -77
  117. re_common/libtest/baseodbc_test.py +7 -7
  118. re_common/libtest/basepandas_test.py +38 -38
  119. re_common/libtest/get_attr_test/get_attr_test_settings.py +14 -14
  120. re_common/libtest/get_attr_test/settings.py +54 -54
  121. re_common/libtest/idencode_test.py +53 -53
  122. re_common/libtest/iniconfig_test.py +35 -35
  123. re_common/libtest/ip_test.py +34 -34
  124. re_common/libtest/merge_file_test.py +20 -20
  125. re_common/libtest/mfaker_test.py +8 -8
  126. re_common/libtest/mm3_test.py +31 -31
  127. re_common/libtest/mylogger_test.py +88 -88
  128. re_common/libtest/myparsel_test.py +27 -27
  129. re_common/libtest/mysql_test.py +151 -151
  130. re_common/libtest/pymongo_test.py +21 -21
  131. re_common/libtest/split_test.py +11 -11
  132. re_common/libtest/sqlite3_merge_test.py +5 -5
  133. re_common/libtest/sqlite3_test.py +34 -34
  134. re_common/libtest/tomlconfig_test.py +30 -30
  135. re_common/libtest/use_tools_test/__init__.py +2 -2
  136. re_common/libtest/user/__init__.py +4 -4
  137. re_common/studio/__init__.py +4 -4
  138. re_common/studio/assignment_expressions.py +36 -36
  139. re_common/studio/mydash/test1.py +18 -18
  140. re_common/studio/pydashstudio/first.py +9 -9
  141. re_common/studio/streamlitstudio/first_app.py +65 -65
  142. re_common/studio/streamlitstudio/uber_pickups.py +23 -23
  143. re_common/studio/test.py +18 -18
  144. re_common/v2/baselibrary/business_utils/BusinessStringUtil.py +235 -220
  145. re_common/v2/baselibrary/business_utils/baseencodeid.py +100 -100
  146. re_common/v2/baselibrary/business_utils/full_doi_path.py +116 -116
  147. re_common/v2/baselibrary/business_utils/rel_tools.py +6 -6
  148. re_common/v2/baselibrary/decorators/utils.py +59 -59
  149. re_common/v2/baselibrary/helpers/search_packge/NearestNeighbors_test.py +105 -105
  150. re_common/v2/baselibrary/helpers/search_packge/fit_text_match.py +253 -253
  151. re_common/v2/baselibrary/helpers/search_packge/scikit_learn_text_matcher.py +260 -260
  152. re_common/v2/baselibrary/helpers/search_packge/test.py +1 -1
  153. re_common/v2/baselibrary/s3object/baseboto3.py +230 -230
  154. re_common/v2/baselibrary/tools/WeChatRobot.py +95 -95
  155. re_common/v2/baselibrary/tools/ac_ahocorasick.py +75 -75
  156. re_common/v2/baselibrary/tools/concurrency.py +35 -35
  157. re_common/v2/baselibrary/tools/data_processer/base.py +53 -53
  158. re_common/v2/baselibrary/tools/data_processer/data_processer.py +497 -508
  159. re_common/v2/baselibrary/tools/data_processer/data_reader.py +187 -187
  160. re_common/v2/baselibrary/tools/data_processer/data_writer.py +38 -38
  161. re_common/v2/baselibrary/tools/dict_tools.py +44 -44
  162. re_common/v2/baselibrary/tools/dolphinscheduler.py +187 -187
  163. re_common/v2/baselibrary/tools/hdfs_base_processor.py +204 -204
  164. re_common/v2/baselibrary/tools/hdfs_bulk_processor.py +67 -67
  165. re_common/v2/baselibrary/tools/hdfs_data_processer.py +338 -338
  166. re_common/v2/baselibrary/tools/hdfs_line_processor.py +74 -74
  167. re_common/v2/baselibrary/tools/list_tools.py +69 -69
  168. re_common/v2/baselibrary/tools/resume_tracker.py +94 -94
  169. re_common/v2/baselibrary/tools/search_hash_tools.py +54 -54
  170. re_common/v2/baselibrary/tools/text_matcher.py +326 -326
  171. re_common/v2/baselibrary/tools/tree_processor/__init__.py +0 -0
  172. re_common/v2/baselibrary/tools/tree_processor/builder.py +25 -0
  173. re_common/v2/baselibrary/tools/tree_processor/node.py +13 -0
  174. re_common/v2/baselibrary/tools/unionfind_tools.py +60 -60
  175. re_common/v2/baselibrary/utils/BusinessStringUtil.py +196 -196
  176. re_common/v2/baselibrary/utils/api_net_utils.py +270 -270
  177. re_common/v2/baselibrary/utils/author_smi.py +361 -361
  178. re_common/v2/baselibrary/utils/base_string_similarity.py +158 -158
  179. re_common/v2/baselibrary/utils/basedict.py +37 -37
  180. re_common/v2/baselibrary/utils/basehdfs.py +163 -163
  181. re_common/v2/baselibrary/utils/basepika.py +180 -180
  182. re_common/v2/baselibrary/utils/basetime.py +94 -77
  183. re_common/v2/baselibrary/utils/db.py +174 -156
  184. re_common/v2/baselibrary/utils/elasticsearch.py +46 -0
  185. re_common/v2/baselibrary/utils/json_cls.py +16 -16
  186. re_common/v2/baselibrary/utils/mq.py +83 -83
  187. re_common/v2/baselibrary/utils/n_ary_expression_tree.py +243 -243
  188. re_common/v2/baselibrary/utils/string_bool.py +187 -186
  189. re_common/v2/baselibrary/utils/string_clear.py +246 -246
  190. re_common/v2/baselibrary/utils/string_smi.py +18 -18
  191. re_common/v2/baselibrary/utils/stringutils.py +312 -271
  192. re_common/vip/base_step_process.py +11 -11
  193. re_common/vip/baseencodeid.py +90 -90
  194. re_common/vip/changetaskname.py +28 -28
  195. re_common/vip/core_var.py +24 -24
  196. re_common/vip/mmh3Hash.py +89 -89
  197. re_common/vip/proxy/allproxys.py +127 -127
  198. re_common/vip/proxy/allproxys_thread.py +159 -159
  199. re_common/vip/proxy/cnki_proxy.py +153 -153
  200. re_common/vip/proxy/kuaidaili.py +87 -87
  201. re_common/vip/proxy/proxy_all.py +113 -113
  202. re_common/vip/proxy/update_kuaidaili_0.py +42 -42
  203. re_common/vip/proxy/wanfang_proxy.py +152 -152
  204. re_common/vip/proxy/wp_proxy_all.py +181 -181
  205. re_common/vip/read_rawid_to_txt.py +91 -91
  206. re_common/vip/title/__init__.py +5 -5
  207. re_common/vip/title/transform/TransformBookTitleToZt.py +125 -125
  208. re_common/vip/title/transform/TransformConferenceTitleToZt.py +139 -139
  209. re_common/vip/title/transform/TransformCstadTitleToZt.py +195 -195
  210. re_common/vip/title/transform/TransformJournalTitleToZt.py +203 -203
  211. re_common/vip/title/transform/TransformPatentTitleToZt.py +132 -132
  212. re_common/vip/title/transform/TransformRegulationTitleToZt.py +114 -114
  213. re_common/vip/title/transform/TransformStandardTitleToZt.py +135 -135
  214. re_common/vip/title/transform/TransformThesisTitleToZt.py +135 -135
  215. re_common/vip/title/transform/__init__.py +10 -10
  216. {re_common-10.0.39.dist-info → re_common-10.0.41.dist-info}/LICENSE +201 -201
  217. {re_common-10.0.39.dist-info → re_common-10.0.41.dist-info}/METADATA +16 -16
  218. re_common-10.0.41.dist-info/RECORD +252 -0
  219. {re_common-10.0.39.dist-info → re_common-10.0.41.dist-info}/WHEEL +1 -1
  220. re_common-10.0.39.dist-info/RECORD +0 -248
  221. {re_common-10.0.39.dist-info → re_common-10.0.41.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错误,检查逻辑")