大家好,并发编程 进入第三篇。

上班第一天,大家应该比较忙吧。小明也是呢,所以今天的内容也很少。只要几分钟就能学完。

昨天我们说,线程与线程之间要通过消息通信来控制程序的执行。

G讲完了消息通信,今天就来探讨下线程里的信息隔离是如何做到的。

大家注意
信息隔离,这并不是官方命名的名词,也不是网上广为流传的名词。是我为了方便理解而自创的,大家知道就好咯。

本文目录


  • 初步认识信息隔离
  • 信息隔离的意义何在

. 初步认识信息隔离

什么是信息隔离
比如说,咱有两个线程,线程A里的变量,和线程B里的变量值不能共享。这就是信息隔离

你可能要说,那变量名取不一样不就好啦?

是的,如果所有的线程都不是由一个class实例化出来的同一个对象,确实是可以。这个问题我们暂且挂着,后面我再说明。

那么,如何实现信息隔离呢?
在Python中,其提供了threading.local这个类,可以很方便的控制变量的隔离,即使是同一个变量,在不同的线程中,其值也是不能共享的。

用代码来看下

from threading import local, Thread, currentThread

# 定义一个local实例
local_data = local()
# 在主线中,存入name这个变量
local_data.name = 'local_data' class MyThread(Thread):
def run(self):
print("赋值前-子线程:", currentThread(),local_data.__dict__)
# 在子线程中存入name这个变量
local_data.name = self.getName()
print("赋值后-子线程:",currentThread(), local_data.__dict__) if __name__ == '__main__':
print("开始前-主线程:",local_data.__dict__) t1 = MyThread()
t1.start()
t1.join() t2 = MyThread()
t2.start()
t2.join() print("结束后-主线程:",local_data.__dict__)

来看看输出结果

开始前-主线程: {'name': 'local_data'}

赋值前-子线程: <MyThread(Thread-1, started 4832)> {}
赋值后-子线程: <MyThread(Thread-1, started 4832)> {'name': 'Thread-1'} 赋值前-子线程: <MyThread(Thread-2, started 5616)> {}
赋值后-子线程: <MyThread(Thread-2, started 5616)> {'name': 'Thread-2'} 结束后-主线程: {'name': 'local_data'}

从输出来看,我们可以知道,local实际是一个字典型的对象,其内部可以以key-value的形式存入你要做信息隔离的变量。local实例可以是全局唯一的,只有一个。因为你在给local存入或访问变量时,它会根据当前的线程的不同从不同的存储空间存入或获取。

基于此,我们可以得出以下三点结论:

  1. 主线程中的变量,不会因为其是全局变量,而被子线程获取到;
  2. 主线程也不能获取到子线程中的变量;
  3. 子线程与子线程之间的变量也不能互相访问。

所以如果想在当前线程保存一个全局值,并且各自线程(包括主线程)互不干扰,使用local类吧。

. 信息隔离的意义何在

细心的你,一定已经发现了,上面那个例子,即使我们不用threading.local来做信息隔离,两个线程self.getName()本身就是隔离的,没有任何关系的。因为这两个线程是由一个class实例出的两个不同的实例对象。自然是可以不用做隔离,因为其本身就是隔离的。

但是,现实开发中。不可排除有多个线程,是由一个class实例出的同一个实例对象而实现的。

譬如,现在新手特别喜欢的爬虫项目。通常都是先给爬虫一个主页,然后获取主页下的所有链接,对这个链接再进行遍历,一直往下,直到把所有的链接都爬完,获取到我们所需的内容。

由于单线程的爬取效率实在是太低了,我们考虑使用多线程来工作。先使用socketwww.sina.con.cn建立一个TCP连接。然后在这个连接的基础上,对主页上的每个链接(我们这里只举news.sina.com.cnblog.sina.com.cn这两个子链接做例子)创建一个线程,这样效率就高多了。

友情提醒
以下代码,若要理解,可能需要你了解下socket的网络编程相关内容。我在前几天的文章中有发布一篇相关的文章,没有基础的同学可以先去看看那篇文章。

import threading
from functools import partial
from socket import socket, AF_INET, SOCK_STREAM class LazyConnection:
def __init__(self, address, family=AF_INET, type=SOCK_STREAM):
self.address = address
self.family = AF_INET
self.type = SOCK_STREAM
self.local = threading.local() def __enter__(self):
if hasattr(self.local, 'sock'):
raise RuntimeError('Already connected')
# 把socket连接存入local中
self.local.sock = socket(self.family, self.type)
self.local.sock.connect(self.address)
return self.local.sock def __exit__(self, exc_ty, exc_val, tb):
self.local.sock.close()
del self.local.sock def spider(conn, website):
with conn as s:
header = 'GET / HTTP/1.1\r\nHost: {}\r\nConnection: close\r\n\r\n'.format(website)
s.send(header.encode("utf-8"))
resp = b''.join(iter(partial(s.recv, 100000), b''))
print('Got {} bytes'.format(len(resp))) if __name__ == '__main__':
# 建立一个TCP连接
conn = LazyConnection(('www.sina.com.cn', 80)) # 爬取两个页面
t1 = threading.Thread(target=spider, args=(conn,"news.sina.com.cn"))
t2 = threading.Thread(target=spider, args=(conn,"blog.sina.com.cn"))
t1.start()
t2.start()
t1.join()
t2.join()

输出结果

Got 765 bytes
Got 513469 bytes

如果是在这种场景下,要做到线程之间的状态信息的隔离,就肯定要借助threading.local,所以threading.local的存在是有存在的意义的。其他还有很多场景是必须借助threading.local才能实现的,而这些就要靠你们在真正的业务开发中去发现咯。

好了,今天就讲这些内容。


Python并发编程之线程中的信息隔离(五)的更多相关文章

  1. 《转载》Python并发编程之线程池/进程池--concurrent.futures模块

    本文转载自Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mult ...

  2. python并发编程之线程/协程

    python并发编程之线程/协程 part 4: 异步阻塞例子与生产者消费者模型 同步阻塞 调用函数必须等待结果\cpu没工作input sleep recv accept connect get 同 ...

  3. Python 之并发编程之线程中

    四.线程锁lock(线程的数据安全) 在数据量较大的时候,线程中的数据会被并发,所有数据会不同步,以至于数据会异常. 下面还介绍了两种的上锁方法. 例: from threading import T ...

  4. Python并发编程之线程消息通信机制任务协调(四)

    大家好,并发编程 进入第四篇. 本文目录 前言 Event事件 Condition Queue队列 总结 . 前言 前面我已经向大家介绍了,如何使用创建线程,启动线程.相信大家都会有这样一个想法,线程 ...

  5. python并发编程之线程

    操作系统线程理论 参考资料:http://www.cnblogs.com/Eva-J/articles/8306047.html 线程和python 理论知识 全局解释器锁GIL Python代码的执 ...

  6. Python并发编程-进程 线程 同步锁 线程死锁和递归锁

    进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...

  7. python并发编程之线程(二):死锁和递归锁&信号量&定时器&线程queue&事件evevt

    一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...

  8. python 并发编程 多线程 线程理论

    操作系统比作一家公司,进程相当于一个部门  线程相当于一个部门的成员 进程之间是互相隔离的 一 什么是线程 1. 每启动一个进程 至少有一个线程,  在传统操作系统中,每个进程有一个地址空间,而且默认 ...

  9. python并发编程之线程(一):线程&守护线程&全局解释器锁

      一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 官网链接:https://docs.pyth ...

随机推荐

  1. Linux Shell 命令--rename

    重命名文件,经常用到mv命令,批量重命名文件rename是最好的选择,Linux的rename 命令有两个版本,一个是C语言版本的,一个是Perl语言版本的,判断方法:输入man rename 看到第 ...

  2. 通过iframe引入另外一个项目中的html片段到项目中,解决样式,高度,兼容等问题的策略

     <!--尾部开始--> <iframe src="http://172.16.24.11:9000/cartoon-web/footer_new"    m ...

  3. 实用Android 屏幕适配方案分享

    转载地址:http://blog.csdn.net/gao_chun/article/details/45645051 真正可用,并且简单易行,可以在多个屏幕大小和屏幕密度上有良好表现的Android ...

  4. Java集合之WeakHashMap

    纸上得来终觉浅,绝知此事要躬行  --陆游    问渠那得清如许,为有源头活水来  --朱熹 WeakHashMap继承于AbstractMap,同时实现了Map接口. 和HashMap一样,Weak ...

  5. Struts2中的缓存----以Injector为例

    题外话,文章中有大量的标识1 标识2,大家可以用ctrl+f来查找. 构成缓存的类 主要就是以下两个: com.opensymphony.xwork2.inject.util.ReferenceCac ...

  6. *** non-numeric second argument to `wordlist' function: ''. Stop错误解决办法

    PS: 解决办法搜集自:stackoverflow website:http://stackoverflow.com/questions/5677178/ndk-gdb-fails-with-mess ...

  7. 【Android 应用开发】自定义View 和 ViewGroup

    一. 自定义View介绍 自定义View时, 继承View基类, 并实现其中的一些方法. (1) ~ (2) 方法与构造相关 (3) ~ (5) 方法与组件大小位置相关 (6) ~ (9) 方法与触摸 ...

  8. Linux管线命令 - cut,grep,sort,uniq,wc,tee,tr,col,join,paste,expand,split,xargs

    在每个管线后面接的第一个数据必定是『命令』喔!而且这个命令必须要能够接受 standard input 的数据才行,这样的命令才可以是为『管线命令』,例如 less, more, head, tail ...

  9. navicat里导入和导出.sql文件

    一:Navicat导入MySQL的.sql文件. 打开连接connection,选择你要导入的数据库,双击打开(或者新建一个),然后右键该数据库,选"运行批次任务文件(execute sql ...

  10. Xcode 下删除Provisioning Profiles文件

    Xcode 中有很多不可以用的Provisioning Profiles 文件,每次选择手机证书时,看着那么长的菜单很烦有木有? 在Xcode 5中删除 Provisioning Profiles,打 ...