import time
import multiprocessing device = ['3695a1c7-0fa6-4fa8-a563-8fd462c04af5', '0dfdd431-f9bc-4c90-b246-f2b19d20969c', '0323488d-7c9c-4244-8fc6-07266124d2f0', '689cde3c-6ca4-4ed7-b63a-e114b76650fb', 'bc4084a5-da8e-4673-a214-4b5f5de4b21d', 'b6ec0d69-af49-43d1-b77d-e72da48df2e6', 'a7fe06e8-ff26-4ebf-b526-ca7083ccb031', '7a8db973-6a7b-481b-ba80-0afb5594b6cd', '637db54f-9932-4d8e-8b87-5c92011578e9', '506b79bd-e174-4c24-8e39-9410ef7ef1f2'] def do_hash(d):
print("%s %d %d %d" % (d, hash(d), hash(d), hash(d)%10))
time.sleep(0.01) res, pool = [], multiprocessing.Pool(processes=len(device))
for d in device:
do_hash(d)
for i in range(10):
res.append(pool.apply_async(do_hash, args=(d,))) while res:
for ret in res:
if ret.ready():
res.remove(ret)
time.sleep(0.01)

如上代码,用来验证hash的结果。

  • 在同一个程序运行过程中,单进程下,hash同一个字符串,结果是否一致。 答案:一致
  • 在同一个程序运行过程中,多进程中,不同子进程hash同一个字符串,结果是否一致。答案:一致
  • 同样的代码,多次运行同一个程序,每次运行程序时,hash同一个字符串,产生的结果和其他运行过程产生的结果是否一致。答案:不一致

如下是运行测试。

  • 运行一次
$python3 ~/t.py |sort |uniq -c
11 0323488d-7c9c-4244-8fc6-07266124d2f0 -6009992680465351322 -6009992680465351322 8
11 0dfdd431-f9bc-4c90-b246-f2b19d20969c -5508606457111079556 -5508606457111079556 4
11 3695a1c7-0fa6-4fa8-a563-8fd462c04af5 4707712037038632691 4707712037038632691 1
11 506b79bd-e174-4c24-8e39-9410ef7ef1f2 857824721138771069 857824721138771069 9
11 637db54f-9932-4d8e-8b87-5c92011578e9 5754536697633125890 5754536697633125890 0
11 689cde3c-6ca4-4ed7-b63a-e114b76650fb 5254068311346342848 5254068311346342848 8
11 7a8db973-6a7b-481b-ba80-0afb5594b6cd 6569556914358930293 6569556914358930293 3
11 a7fe06e8-ff26-4ebf-b526-ca7083ccb031 -7752949605389894777 -7752949605389894777 3
11 b6ec0d69-af49-43d1-b77d-e72da48df2e6 5391450356066231067 5391450356066231067 7
11 bc4084a5-da8e-4673-a214-4b5f5de4b21d 8663379699579545061 8663379699579545061 1
  • 再运行一次:
$ python3 ~/t.py |sort |uniq -c
11 0323488d-7c9c-4244-8fc6-07266124d2f0 6637200495818958087 6637200495818958087 7
11 0dfdd431-f9bc-4c90-b246-f2b19d20969c 2550085777036819750 2550085777036819750 0
11 3695a1c7-0fa6-4fa8-a563-8fd462c04af5 3291757742095134676 3291757742095134676 6
11 506b79bd-e174-4c24-8e39-9410ef7ef1f2 -1500680899775158570 -1500680899775158570 0
11 637db54f-9932-4d8e-8b87-5c92011578e9 -1846084821474967397 -1846084821474967397 3
11 689cde3c-6ca4-4ed7-b63a-e114b76650fb -8218022715868473813 -8218022715868473813 7
11 7a8db973-6a7b-481b-ba80-0afb5594b6cd -783003051379698560 -783003051379698560 0
11 a7fe06e8-ff26-4ebf-b526-ca7083ccb031 -4314803525216302877 -4314803525216302877 3
11 b6ec0d69-af49-43d1-b77d-e72da48df2e6 1699421278255228297 1699421278255228297 7
11 bc4084a5-da8e-4673-a214-4b5f5de4b21d 6135446317717420100 6135446317717420100 0

原因是:

python的字符串hash算法并不是直接遍历字符串每个字符去计算hash,而是会有一个secret prefix和一个secret suffix,可以认为相当于是给字符串加盐后做hash,可以规避一些规律输入的情况显然这个secret前后缀的值会直接影响计算结果,而且它有一个启动时随机生成的机制,只不过,在2.x版本中,这个机制默认是关闭的,前后缀每次启动都设置为0,除非你改了相关环境变量来要求随机,而在3.x中修改了默认行为,如果你不配置环境变量,则默认是随机一个前后缀值,这样每次启动都会不同这个环境变量是PYTHONHASHSEED,无论在2.x还是3.x中,配置为一个正整数,将作为随机种子;配置为0,则secret前后缀默认清零(和2.x默认行为就一样了),配置为空串或“random”,则表示让进程随机生成(和3.x默认行为一样)具体为啥要这么做,猜测一个是为了安全性(防字符串hash表的攻击,比如php曾经碰到的攻击),另一个可能也是强调不要依赖一些内建结果,因为这种算法可能随着版本而更新,避免有些用户不看文档,误以为是永远不变的

作者:冒泡
链接:https://www.zhihu.com/question/57526436/answer/153241020
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

设置固定的PYTHONHASHSEED后结果一致:

yzc:~ youzhengchuan$ PYTHONHASHSEED=10 python3 ~/t.py |sort |uniq -c
11 0323488d-7c9c-4244-8fc6-07266124d2f0 2141519202912666524 2141519202912666524 4
11 0dfdd431-f9bc-4c90-b246-f2b19d20969c -843959203188636526 -843959203188636526 4
11 3695a1c7-0fa6-4fa8-a563-8fd462c04af5 5124534335560792207 5124534335560792207 7
11 506b79bd-e174-4c24-8e39-9410ef7ef1f2 -8435934314154906615 -8435934314154906615 5
11 637db54f-9932-4d8e-8b87-5c92011578e9 -8619377286856168125 -8619377286856168125 5
11 689cde3c-6ca4-4ed7-b63a-e114b76650fb 9094422155202130727 9094422155202130727 7
11 7a8db973-6a7b-481b-ba80-0afb5594b6cd 1077850608746704706 1077850608746704706 6
11 a7fe06e8-ff26-4ebf-b526-ca7083ccb031 -4716484918100210177 -4716484918100210177 3
11 b6ec0d69-af49-43d1-b77d-e72da48df2e6 -5676381002318020516 -5676381002318020516 4
11 bc4084a5-da8e-4673-a214-4b5f5de4b21d 4107242733003648281 4107242733003648281 1
yzc:~ youzhengchuan$ PYTHONHASHSEED=10 python3 ~/t.py |sort |uniq -c
11 0323488d-7c9c-4244-8fc6-07266124d2f0 2141519202912666524 2141519202912666524 4
11 0dfdd431-f9bc-4c90-b246-f2b19d20969c -843959203188636526 -843959203188636526 4
11 3695a1c7-0fa6-4fa8-a563-8fd462c04af5 5124534335560792207 5124534335560792207 7
11 506b79bd-e174-4c24-8e39-9410ef7ef1f2 -8435934314154906615 -8435934314154906615 5
11 637db54f-9932-4d8e-8b87-5c92011578e9 -8619377286856168125 -8619377286856168125 5
11 689cde3c-6ca4-4ed7-b63a-e114b76650fb 9094422155202130727 9094422155202130727 7
11 7a8db973-6a7b-481b-ba80-0afb5594b6cd 1077850608746704706 1077850608746704706 6
11 a7fe06e8-ff26-4ebf-b526-ca7083ccb031 -4716484918100210177 -4716484918100210177 3
11 b6ec0d69-af49-43d1-b77d-e72da48df2e6 -5676381002318020516 -5676381002318020516 4
11 bc4084a5-da8e-4673-a214-4b5f5de4b21d 4107242733003648281 4107242733003648281 1
yzc:~ youzhengchuan$ PYTHONHASHSEED=10 python3 ~/t.py |sort |uniq -c
11 0323488d-7c9c-4244-8fc6-07266124d2f0 2141519202912666524 2141519202912666524 4
11 0dfdd431-f9bc-4c90-b246-f2b19d20969c -843959203188636526 -843959203188636526 4
11 3695a1c7-0fa6-4fa8-a563-8fd462c04af5 5124534335560792207 5124534335560792207 7
11 506b79bd-e174-4c24-8e39-9410ef7ef1f2 -8435934314154906615 -8435934314154906615 5
11 637db54f-9932-4d8e-8b87-5c92011578e9 -8619377286856168125 -8619377286856168125 5
11 689cde3c-6ca4-4ed7-b63a-e114b76650fb 9094422155202130727 9094422155202130727 7
11 7a8db973-6a7b-481b-ba80-0afb5594b6cd 1077850608746704706 1077850608746704706 6
11 a7fe06e8-ff26-4ebf-b526-ca7083ccb031 -4716484918100210177 -4716484918100210177 3
11 b6ec0d69-af49-43d1-b77d-e72da48df2e6 -5676381002318020516 -5676381002318020516 4
11 bc4084a5-da8e-4673-a214-4b5f5de4b21d 4107242733003648281 4107242733003648281 1

python hash 每次调用结果不一样的更多相关文章

  1. python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

    python与java的内存机制不一样;java的方法会进入方法区直到对象消失 方法才会消失;python的方法是对象每次调用都会创建新的对象 内存地址都不i一样

  2. Python包模块化调用方式详解

    Python包模块化调用方式详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一般来说,编程语言中,库.包.模块是同一种概念,是代码组织方式. Python中只有一种模块对象类型 ...

  3. Shodan搜索引擎详解及Python命令行调用

    shodan常用信息搜索命令 shodan配置命令 shodan init T1N3uP0Lyeq5w0wxxxxxxxxxxxxxxx //API设置 shodan信息收集 shodan myip ...

  4. python笔记之调用系统命令

    python笔记之调用系统命令 目前我使用到的python中执行cmd的方式有三种 使用os.system("cmd") 该方法在调用完shell脚本后,返回一个16位的二进制数, ...

  5. 每次调用fork()函数之后,父线程和创建出的子线程都是从fork()后开始执行

    Linux下多少个"-"将被打印: 1 2 3 4 5 6 7 8 int main(void){   int i;   for(i=0;i<4;i++){   fork() ...

  6. python可变参数调用函数的问题

    已使用python实现的一些想法,近期使用python这种出现的要求,它定义了一个函数,第一种是一般的参数,第二个参数是默认,并有可变参数.在第一项研究中python时间,不知道keyword可变参数 ...

  7. python发布及调用基于SOAP的webservice

    现如今面向服务(SOA)的架构设计已经成为主流,把公用的服务打包成一个个webservice供各方调用是一种非常常用的做法,而应用最广泛的则是基于SOAP协议和wsdl的webservice.本文讲解 ...

  8. python 程序中调用go

    虽然python优点很多,但是有一个致命的缺点就是运行速度太慢,那么python程序需要一些计算量比较大的模块时一般会调用c或者c++的代码来重写,但是c/c++编写代码代价太高,耗费太多的人力.那么 ...

  9. 如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样)

    如何在Python脚本中调用外部命令(就像在linux shell或Windows命令提示符下输入一样) python标准库中的subprocess可以解决这个问题. from subprocess ...

随机推荐

  1. C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能

    本文通过ANTS Memory Profiler工具探索c#中+.string.Concat.string.Format.StringBuilder.Append四种方式进行字符串拼接时的性能. 本文 ...

  2. 用 Portainer 远程管理 docker

    参考的官网地址为:https://portainer.readthedocs.io/en/stable/deployment.html 先更新Centos docker 镜像加速地址: curl -s ...

  3. 第四章·Kibana入门-安装,索引添加及界面功能

    1.Kibana简介及部署 什么是Kibana? Kibana是一个通过调用elasticsearch服务器进行图形化展示搜索结果的开源项目. Kibana安装及配置 #将Kibana安装包上传至服务 ...

  4. JS笔记02

    回顾: html: 超文本标记语言 后缀名: *.html 或 *.htm 标签分类: 围堵标签: 双标签 <html>标签体</html> 空标签: 单标签 <br/& ...

  5. 【2017-03-28】JS基础、windows对象、history对象、location对象

    一.JS基础 JS - javaScript 1.js功能: 1).进行数据的运算.2).控制浏览器的一些功能.3).控制元素(属性.内容.样式) js引用位置: 可以放在html页的任意位置. 推荐 ...

  6. 一、CentOS 7安装部署GitLab服务器

    一.CentOS 7安装部署GitLab服务器 1.安装依赖软件 yum -y install policycoreutils policycoreutils-python openssh-serve ...

  7. 并发编程:协程TCP、非阻塞IO、多路复用、

    一.线程池实现阻塞IO 二.非阻塞IO模型 三.多路复用,降低CPU占用 四.模拟异步IO 一.线程池实现阻塞IO 线程阻塞IO 客户端 import socket c = socket.socket ...

  8. TextView跑马灯

    TextView跑马灯 textView跑马灯实现:1.定义textView标签的4个属性:android:singleLine="true"//使其只能单行android:ell ...

  9. 1.Lucene简介

    1.Lucene简介 Lucene是一个基于Java的全文信息检索工具包,它不是一个完整的搜索应用程序,而是为你的应用程序提供索引和搜索功能 Lucene是开源项目,它是可扩展,高性能的库用于索引和搜 ...

  10. windows 快捷键收集

    1. 放大镜 windows徽标 + "+“ 2. 直接显示桌面 windows徽标 + D 3. 收起所有窗口 windows徽标 + M 4. 浏览器中恢复之前关闭的页面 Ctrl + ...