1
noneusername 2023-06-02 01:40:46 +08:00
边看文档,边让 GPT 输出示例测试
|
2
ysc3839 2023-06-02 02:03:57 +08:00 via Android 1
CPU 密集运算用 Python 的多线程是没用的,需要多进程
这种情况手动分段然后开多几个同时跑就好了 |
3
Weixiao0725 2023-06-02 02:15:59 +08:00 1
看一下 multiprocessing.Pool
|
4
suith27 2023-06-02 02:19:25 +08:00 via iPhone
可以研究一下 multiprocessing: https://docs.python.org/zh-cn/3/library/multiprocessing.html
|
5
shalingye 2023-06-02 03:28:45 +08:00 via Android
你需要的是多进程,简单得很,这是我的模板:
if __name__=='__main__': from multiprocessing import Pool # 导入进程池 path=choosefolder() p = Pool() # 创建进程池,留空代表 Cpu 的逻辑内核数目 while True: try: for n in range(1,1000): p.apply_async(download, args=(n,path)) # 向进程池中添加任务 except: p.close() # 结束向进程池中添加任务(后续不能再使用 apply_async 方法添加新任务) p.join() # 实现进程同步 break |
6
shalingye 2023-06-02 03:33:46 +08:00 via Android
缩进寄了,自己排吧,choosefolder 和 download 都是函数名,args 代表 download 函数的参数,如果只有一个参数需要写成 n,的形式,把你需要分割处理的函数替换到 download 的位置
|
7
fyq 2023-06-02 06:22:27 +08:00
如果只有一个文档的话,最简单的方法是手动拆分成好几个,然后同时针对拆分后不同的的文档运行你的程序去分析,时候再针对得到的结果汇总一下就好了。
|
8
liyafe1997 2023-06-02 06:38:04 +08:00 2
Python 的多线程是假的,忘了这东西吧,要干正事得看多进程 multiprocessing.Pool
|
9
lovelylain 2023-06-02 08:28:04 +08:00 via Android
python 有个著名的 GIL 锁,执行 Python 代码时都需要先获取这个锁,所以虽然多线程,但同一时间只有一个线程获得这个锁,其他线程都在等待,结果只能跑满一个核。如果你是 c 模块处理,可以手动释放锁处理完再获取,这样多线程就能突破单核限制。但 c 模块开发效率和可移植性很差,更好的方案是上面提到的 multiprocessing 多进程。
|
10
tulongtou 2023-06-02 08:29:29 +08:00
卧槽,现在文科生都这么优秀了么,卷到理科生这边来了
|
11
litguy 2023-06-02 08:33:23 +08:00
多进程,每个进程处理其中的一部分东西,最后所有进程结果汇总
|
12
strawberrydafu 2023-06-02 08:34:04 +08:00
检索具体是在干什么?半小时才 3 万字我怀疑算法本身有很多优化空间
|
13
Kinnice 2023-06-02 08:39:30 +08:00 via Android 2
词汇统计,m1 ,半小时 3w 字,看起来算法不像是没有问题
|
14
ohayoo 2023-06-02 08:40:27 +08:00
其实可以用第三方的任务队列库,自带多进程多线程选项,只需要关注自己的逻辑函数即可,都可以尝试对比下
|
15
adoni 2023-06-02 11:15:57 +08:00
参见: https://adoni.github.io/2019/01/07/python-practice/#concurrent-and-multi-process
```python from concurrent.futures import ProcessPoolExecutor with ProcessPoolExecutor(max_workers=16) as exe: result = exe.map(func, data_list) ``` 另外,你可以直接改成单线程,看一下,我感觉 130 万字,分分钟跑完。 |
16
aijam 2023-06-02 11:54:43 +08:00
"半个小时才检索到三万多字",这得多慢啊,口算可能都比这个快
|
17
coderluan 2023-06-02 12:27:34 +08:00
这个你问 chatgpt 更方便,最简单应该是 concurrent.futures.ThreadPoolExecutor ,然后用 subprocess 调用你的程序开多进程。
|
18
killva4624 2023-06-02 12:30:22 +08:00
多进程记得考虑进程安全
|
19
laqow 2023-06-02 12:46:52 +08:00
会不会算法其实有问题?至少 python 原生的文件 IO 和字符串处理慢的一匹,直接把所有文字 read 进内存再处理,或者以二进制读取后在 byte 对象上搜索都能快出个十倍来
|
20
iX8NEGGn 2023-06-02 14:13:32 +08:00 via iPhone
半小时三万多字,算法肯定有问题。百万字算法合适的话也,词频统计也就几十秒
|
21
lyz1990 2023-06-02 14:26:19 +08:00
半小时 3 万慢得不太正常
|
22
pathetique OP @Kinnice @Weixiao0725 @adoni @aijam @coderluan @fyq @killva4624 @laqow @litguy @liyafe1997
非常感谢各位的帮助!就不一一回复,几位大佬我一起感谢先 先非常感谢对多线程和进程的区分,我已经开始用 multiprocessing module 了,在我的 M1max 上基本上十个小时可以做完,对于雍正可以接受了。但是随着搜索对象正则式的复杂化我怀疑还要更久更久,而且雍正才干几年,乾隆的起居录估计有十倍大,可能个人电脑还是不够。 然后几位大佬怀疑算法有没有问题,我也不知道哪里可以改善的。我把最简单的版本(算二字成词率)代码放在这里,辣大家的眼可能,但是真心请问如果有耐心看完的大佬:有没有改进的空间?如果是单线程的话,我可以从头到尾扫描,扫过的不再碰,复杂度是 n^2/2 ,但是因为多线程,把文本分成多块就没头没尾的,复杂度是 n^2 但是可以多核平均。 checkdict = [] #已经查过的单词词库 list = [] #文本本身 step = 100000 #每个机器人负责多大块 with open('yong3.txt', 'r') as file: contents = file.read() for chr in contents: if chr != '\n' and chr != ' ' and chr != '。' and chr != '、' and chr != '○' and chr != '\u3000': #有些奇怪的字符去掉 list.append(chr) length = len(list) #雍正大概 100 万字 import multiprocessing.pool #import the multiprocessing module def worker(num): """Worker function for the process""" print(f'Worker {num} starting') count = 0 for i in range(0+step*num,min(step+step*num,length-2)): #每个机器人负责 #step 长度的文字 if (list[i:i+2] not in checkdict): #如果不在字典里 count = 0 for j in range(0,length-2): #全本比对,因为分块似乎只能这么做,不能从 i 开始? if list[i:i+2] == list[j:j+2]: count = count + 1 checkdict.append(list[i:i+2]) #check 完,添进已查字典 if count > 350: #出现次数高于 350 次的字显示出来 print (list[i:i+2]) print(i, count, f"{num}th worker at percentage = {format((i/step-num)*100, '.2f')}%" ) print(f'Worker {num} finished') 还是挺好玩的,发现很多有趣的事实,比如弄死了年羹尧雍正还常提,比如他喜欢的十三弟其实没那么常提。我其实拿清史资料是因为手头方便,下一步更想用 Colibri Core 处理黏着语(黏着语,比中文不一样的地方在于一个词根会有很多变化,比如 love, loves, loving )。 想问调用 Calobri Core 这样的库啊包的各位大佬还有什么建议呢?还是照着 ChatGPT 的做?(我的 Python 真的很生,刚学,小时候会用 c ) 然后想问下,如果有人有时间帮小的看了这个案例,这种算法用显卡( CUDA )来帮助做会有帮助吗?或者我下一步弄大了,比如一千万字的更加模糊的搜索(比如犹太注经动辄几千万),有什么好的建议提速呢?可以借学校的服务器或者云吗?但是感觉云的 CPU 频率应该也一般。 非常感谢大家指路!小的刚刚用电脑编程对付这些,求拍求建议求更多工具。 |
23
Kinnice 2023-06-02 14:55:23 +08:00
@pathetique #22 首先是做中文分词 eg: https://github.com/fxsjy/jieba ,然后应该可以非常快,提供个 datasource ?。
|
24
julyclyde 2023-06-02 14:59:53 +08:00
分词这事有前后顺序依赖吧,能多线程??
|
26
zhzy 2023-06-02 18:13:53 +08:00
看了一下,没做分词,直接每两个字作为一个词;
用 list 循环判断是否存在,而且文本里没有重复的文字么,用两个 for 循环感觉没什么必要,相当于每个词都翻一遍全文,O(n^2),不慢才怪吧。其实直接一个循环然后字典里+1 就行了,虽然也怪怪的,但是至少比现在的快; 其实还是建议不要自己写,或者至少了解一下这类算法应该怎么写...完全用自己的思路闷头搞有时候真的不容易意识到代码里的问题...要不还是老老实实上 NLP 库 |
27
ispinfx 2023-06-02 18:28:05 +08:00
这么点体量多进程要跑 10 小时?
|
28
zhzy 2023-06-02 18:29:14 +08:00
@zhzy Python 不是 c ,很多东西不需要自己实现的,而且尽量不要用内置的类型作为变量名,快速糊了一个版本,应该会快一些。
|
30
hellojukay 2023-06-02 18:34:53 +08:00
1. list 如果长度非常的长,可能话很多时间在增长扩容上,建议使用 linklist
2. if xx in [] , 这种判断方式效率非常低,应该使用 hash 的方式 |
31
pathetique OP @zhzy 谢过,我去试试用 panda !不用中文的分词 library 是因为用中文只是试试,其实主业是古代西方语言,最后需要 n-gram skipgram flexgram 之类的还是要自己微调很多自己写然后穷尽搜索。请问 regex 或者 panda 有好的入门建议吗?还,就 GPT 就好?
|
32
pathetique OP @hellojukay 感恩,我马上学一下 linklist 和 hash……
|
33
zhzy 2023-06-02 18:40:57 +08:00
@pathetique #31 如果只是处理一下停用词的话就一两行代码,不需要学,抄一下就行,百万字其实很少的,只要避免循环嵌套这种性能问题不大的
|
35
ispinfx 2023-06-02 18:53:41 +08:00
不知道你是不是要 28 楼这种效果,100 万字跑了也就 0.几秒。
|
37
liyanm169gd 2023-06-02 19:02:31 +08:00
猜一下 OP 的意思,如果是每两个字取下来然后统计频率可以这样做,假定你已经把文本读到了变量 tmpstr 里,total = [tmpstr[i]+tmpstr[i+1] for i in range(0,len(a)-1,2)],如果要统计可以直接 set ,然后拿 set 的值当 dict 的 key ,value 是 total.count("这里是 key")
|
38
zhzy 2023-06-02 19:25:54 +08:00
@ispinfx #36 是的,可以直接根据文本构造一个步长为 1 每个元素长度为 2 的 list ,然后 Counter 就行,不过那样逻辑就被隐藏掉了,OP 的代码主要问题是扫描 list 来计数,这里只是展示一下更合理的逻辑
|
40
pathetique OP @zhzy 跑通了,非常感谢!但是您的代码我还在慢慢理解中……因为不太理解 counter.get 或者 counter.items 这样的命令。是需要去 pathlib 的档案找意思吗?
|
41
pathetique OP |
42
pathetique OP 再问一个白痴问题,我和您方案的最大差别是不是创建的对象是不是 hashable 的差别?大概就是 30 楼大哥说 list 的效率低,hash 效率高的问题?
非常非常感谢两位的时间!知道大家都挺忙…… |
43
pathetique OP 奇怪为啥有些帖子回复发不出去说要注册 1001 天……1001nights 吗……
|
44
zhzy 2023-06-02 20:39:04 +08:00
@pathetique #40 pathlib 是一个文件系统路径库,封装了一些比较方便的功能,比如可以直接读取文本,用来代替 with...as f: f.read ;
counter 是一个字典,对于一个字典对象 d ,d.items 是取出每一项的键(key)和值(value) for k, v in d.items()这个循环相当于逐一取出字典的每一项 counter.get(key, defaultValue)实际上可以理解为 if key in counter.keys: counter[key]; else: return defaultValue, 作用是尝试根据键读取字典的一个值,如果不存在这样的键, 返回 defaultValue 在 python 里其实这类方法很多, 可以节省很多代码量, 并且速度要比你自己写的逻辑快, 因为在底层它可能会做一些优化 |
45
zhzy 2023-06-02 20:40:56 +08:00
@ispinfx #39 啊 我明白您的意思了, 其实我的意思是 collections.Counter 是可以直接传一个可迭代对象或者 map 的, 比如传一个 str 或 list 进去就可以直接做计算
|
46
aitianci 2023-06-02 20:55:38 +08:00
@Kinnice #23 我玩了一下,用 jieba 出来的效果还不如 re 。我是从网上下载的一个 2MB 多的雍正实录,到 115 卷就没了。jieba 给出的全是单字词,像“朕,等,为,有”这种,re 能给“出谕内阁,应如所请,寻议,下部知之,入祠致祭如例,均应如所请,缘事革职,谕大学士等,给银建坊”这种还有点含义的词组。
|
47
LaurelHarmon 2023-06-02 20:57:43 +08:00 1
笑死,这点数据量,跟多线程、多进程没半毛钱关系,你还是先理清楚需求,然后改一下代码。正常情况秒秒钟出来,暴力循环不可取。
|
48
pathetique OP @aitianci 嗯嗯,其实最大的价值、不是在于观察已有的成形的 pattern 或者单词,而恰恰是一些直观不熟悉但统计上又显著的词汇、语法结构或者说法。比如很多语言中动词-主语-宾语顺序多,但某些地方开始突然高密度调用其他语序;或者很多语言的果-因表达多,但如果突然用因-果连词;或者突然用佶屈聱牙的、甚至字典上没有的词,就很可能有很重要的、非母语者不容易看出的情绪或者信息。反常的信息最珍贵
|
49
pathetique OP @zhzy 非常感谢,我去读下 pathlib 的文档~
|
50
Deplay 2023-06-03 00:24:05 +08:00
单从实现这个任务来讲,使用现成的 wheel 更好的选择,自己写还是很难的,例如#23 所提及的 jieba
也可以考虑上 nlp ,nltk 应该就可以(这一块没怎么接触过,不是很清楚) 至于你提到用 gpu 处理,理论上确实可以,但没必要,毕竟不是很复杂的任务,dl 没必要,学习成本过高 |
52
phoulx 2023-06-03 17:52:42 +08:00
#48 感觉 up 做的东西很有意思呢,之前专业相关,Python 也懂一点。看上去主楼问题已经解决了?如果仍有疑问,欢迎联系 https://paste.rs/Zb0gs ,也许可以提供一点帮助!
|
53
klion 2023-06-03 23:21:44 +08:00
就算文字有 1000 万,也不过不到 100M 的内存,这怎么会 3 万字跑半个小时啊,是不是你自己用了太多 for 做遍历了,看起来更像是你的代码需要优化,你去用 profile 逐行分析代码性能瓶颈再讨论吧
|