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

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

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

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

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

本文目录


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

. 初步认识信息隔离

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

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

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

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

用代码来看下

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

来看看输出结果

  1. 开始前-主线程: {'name': 'local_data'}
  2. 赋值前-子线程: <MyThread(Thread-1, started 4832)> {}
    赋值后-子线程: <MyThread(Thread-1, started 4832)> {'name': 'Thread-1'}
  3. 赋值前-子线程: <MyThread(Thread-2, started 5616)> {}
    赋值后-子线程: <MyThread(Thread-2, started 5616)> {'name': 'Thread-2'}
  4. 结束后-主线程: {'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的网络编程相关内容。我在前几天的文章中有发布一篇相关的文章,没有基础的同学可以先去看看那篇文章。

  1. import threading
    from functools import partial
    from socket import socket, AF_INET, SOCK_STREAM
  2. 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()
  3. 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
  4. def __exit__(self, exc_ty, exc_val, tb):
    self.local.sock.close()
    del self.local.sock
  5. 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)))
  6. if __name__ == '__main__':
    # 建立一个TCP连接
    conn = LazyConnection(('www.sina.com.cn', 80))
  7. # 爬取两个页面
    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()

输出结果

  1. 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. Css详解之(伪类选择器)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. Linux Shell 命令--tr

    tr        用来从标准输入中通过替换或删除操作进行字符转换                -c或--complerment 取代所有不属于第一字符集的字符.                -d ...

  3. python爬虫 - Urllib库及cookie的使用

    http://blog.csdn.net/pipisorry/article/details/47905781 lz提示一点,python3中urllib包括了py2中的urllib+urllib2. ...

  4. How To Transact Move Order Using INV_PICK_WAVE_PICK_CONFIRM_PUB.Pick_Confirm API

    In this Document Goal   Solution   Sample Code:   Steps:   FAQ   References APPLIES TO: Oracle Inven ...

  5. 【云计算 Hadoop】Hadoop 版本 生态圈 MapReduce模型

    忘的差不多了, 先补概念, 然后开始搭建集群实战 ... . 一 Hadoop版本 和 生态圈 1. Hadoop版本 (1) Apache Hadoop版本介绍 Apache的开源项目开发流程 : ...

  6. 使用Ext JS,不要使用页面做组件重用,尽量不要做页面跳转

    今天,有人请教我处理办法,问题是: 一个Grid,选择某条记录后,单击编辑后,弹出编辑窗口(带编辑表单),编辑完成后单击保存按钮保存表单,并关闭窗口,刷新Grid. 这,本来是很简单的,但囿于开发人员 ...

  7. javascript两种声明函数的方式的一次深入解析

    声明函数的方式 javascript有两种声明函数的方式,一个是函数表达式定义函数,也就是我们说的匿名函数方式,一个是函数语句定义函数,下面看代码: /*方式一*/ var FUNCTION_NAME ...

  8. StarUML配置Word生成文档模板

    来源:fasiondog 许多UML建模工具可以自动生成文档,让需求人员.开发人员专心于需求.设计的建模.当然为了能够生成符合自己要求的模板,需对建模时的目录结构(模型和包)有所规划和要求,否则很难生 ...

  9. Mybatis批量插入、批量更新

    合理的使用批量插入.更新对优化有很大的作用,速度明显快了N倍. 数据库连接串后面要新增:&allowMultiQueries=true 批量插入的最大限制主要是看你整条sql占用的大小,所以可 ...

  10. Unity修改Particles Render Material(Unity3D开发之二十三)

    猴子原创,欢迎转载.转载请注明: 转载自Cocos2Der-CSDN,谢谢! 原文地址: http://blog.csdn.net/cocos2der/article/details/48372999 ...