Python并发编程之线程中的信息隔离(五)
大家好,并发编程 进入第三篇。
上班第一天,大家应该比较忙吧。小明也是呢,所以今天的内容也很少。只要几分钟就能学完。
昨天我们说,线程与线程之间要通过消息通信来控制程序的执行。
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存入或访问变量时,它会根据当前的线程的不同从不同的存储空间存入或获取。
基于此,我们可以得出以下三点结论:
- 主线程中的变量,不会因为其是全局变量,而被子线程获取到;
- 主线程也不能获取到子线程中的变量;
- 子线程与子线程之间的变量也不能互相访问。
所以如果想在当前线程保存一个全局值,并且各自线程(包括主线程)互不干扰,使用local类吧。
. 信息隔离的意义何在
细心的你,一定已经发现了,上面那个例子,即使我们不用threading.local来做信息隔离,两个线程self.getName()本身就是隔离的,没有任何关系的。因为这两个线程是由一个class实例出的两个不同的实例对象。自然是可以不用做隔离,因为其本身就是隔离的。
但是,现实开发中。不可排除有多个线程,是由一个class实例出的同一个实例对象而实现的。
譬如,现在新手特别喜欢的爬虫项目。通常都是先给爬虫一个主页,然后获取主页下的所有链接,对这个链接再进行遍历,一直往下,直到把所有的链接都爬完,获取到我们所需的内容。
由于单线程的爬取效率实在是太低了,我们考虑使用多线程来工作。先使用socket和www.sina.con.cn建立一个TCP连接。然后在这个连接的基础上,对主页上的每个链接(我们这里只举news.sina.com.cn和blog.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并发编程之线程中的信息隔离(五)的更多相关文章
- 《转载》Python并发编程之线程池/进程池--concurrent.futures模块
本文转载自Python并发编程之线程池/进程池--concurrent.futures模块 一.关于concurrent.futures模块 Python标准库为我们提供了threading和mult ...
- python并发编程之线程/协程
python并发编程之线程/协程 part 4: 异步阻塞例子与生产者消费者模型 同步阻塞 调用函数必须等待结果\cpu没工作input sleep recv accept connect get 同 ...
- Python 之并发编程之线程中
四.线程锁lock(线程的数据安全) 在数据量较大的时候,线程中的数据会被并发,所有数据会不同步,以至于数据会异常. 下面还介绍了两种的上锁方法. 例: from threading import T ...
- Python并发编程之线程消息通信机制任务协调(四)
大家好,并发编程 进入第四篇. 本文目录 前言 Event事件 Condition Queue队列 总结 . 前言 前面我已经向大家介绍了,如何使用创建线程,启动线程.相信大家都会有这样一个想法,线程 ...
- python并发编程之线程
操作系统线程理论 参考资料:http://www.cnblogs.com/Eva-J/articles/8306047.html 线程和python 理论知识 全局解释器锁GIL Python代码的执 ...
- Python并发编程-进程 线程 同步锁 线程死锁和递归锁
进程是最小的资源单位,线程是最小的执行单位 一.进程 进程:就是一个程序在一个数据集上的一次动态执行过程. 进程由三部分组成: 1.程序:我们编写的程序用来描述进程要完成哪些功能以及如何完成 2.数据 ...
- python并发编程之线程(二):死锁和递归锁&信号量&定时器&线程queue&事件evevt
一 死锁现象与递归锁 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将 ...
- python 并发编程 多线程 线程理论
操作系统比作一家公司,进程相当于一个部门 线程相当于一个部门的成员 进程之间是互相隔离的 一 什么是线程 1. 每启动一个进程 至少有一个线程, 在传统操作系统中,每个进程有一个地址空间,而且默认 ...
- python并发编程之线程(一):线程&守护线程&全局解释器锁
一 threading模块介绍 multiprocess模块的完全模仿了threading模块的接口,二者在使用层面,有很大的相似性,因而不再详细介绍 官网链接:https://docs.pyth ...
随机推荐
- 《java入门第一季》之面向对象静态内部类和非静态内部类的区别
很感谢在内部类章节,"开心阳"先生给与的建议.使用静态内部类.这里就简单说一下静态内部类的使用. package com.devin; public class MyMain{ p ...
- Aidl跨进程通信机制-android学习之旅(87)
Aidl简介 AIDL (Android Interface Definition Language) 是一种IDL 语言,用于生成可以在Android设备上两个进程之间进行进程间通信的代码. 如果在 ...
- AngularJS进阶(二十七)实现二维码信息的集成思路
AngularJS实现二维码信息的集成思路 赠人玫瑰,手留余香.若您感觉此篇博文对您有用,请花费2秒时间点个赞,您的鼓励是我不断前进的动力,与君共勉! 注:点击此处进行知识充电 ...
- STL算法设计理念 - 谓词,一元谓词demo
谓词: 一元函数对象:函数参数1个: 二元函数对象:函数参数2个: 一元谓词 函数参数1个,函数返回值是bool类型,可以作为一个判断式 谓词可以使一个仿函数,也可以是一个回调函数. demo 一元谓 ...
- /dev/null 2>&1的意思(可以直接参考shell重定向那篇,/dev/null是空设备)
路还长 别太狂 以后指不定谁辉煌 2>&1 和 &> 的解释 Linux的IO输入输出有三类 Standard Input 代码 0 Standard Output 代码 ...
- 重装Windows后修复Linux引导
装了双系统(Windows和Linux)的机器重新安装Windows后会导致Linux的引导丢失而无法进入原先的Linux系统[其原因是Windows会覆盖原先MBR中的Linux的BootLoade ...
- 《java入门第一季》之面向对象面试题(面向对象都做了哪些事情)
创建对象内存图解.
- Oracle EBS BOM模块常用表结构
表名: bom.bom_bill_of_materials 说明: BOM清单父项目 BILL_SEQUENCE_ID NUMBER 清单序号(关键字)ASSEMBLY_ITEM_ID NUMBE ...
- Learning ROS for Robotics Programming Second Edition学习笔记(十) indigo Gazebo rviz slam navigation
中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 moveit是书的最后一章,由于对机械臂完全不知,看不懂 ...
- WINCE的批处理
WINCE上没有提供象window一样的bat文件,如果需要类似功能可以借助第三方程序MortScript MortScript是一个运行于WINCE上的免费脚本解释程序,脚本文件为.mscr或.mo ...