线程安全

只能在Winodws下的ipython中演示,Python命令行、Pycharm、Mac下的ipython都演示不出效果

import threading

def worker():
for _ in range(100):
print("{} is running.".format(threading.current_thread().name)) for i in range(1,5):
name = "worker-{}".format(i)
t = threading.Thread(target=worker,name=name)
t.start()

  这里只展示在Windows下ipython中的运行结果:

  对比代码,输出应该是一行一行打印,但是在ipython中有个别行打印时连在了一起。

print属于线程内的语句,且print函数动作分两部分,打印字符串和打印换行,该线程print拼接换行之前被其它线程打断了,这说明print函数是线程不安全的。

简单理解,线程不安全就是正在做某事,被打断了。

线程安全的解决方法:

1、拼接字符串

print("{} is running\n".format(threading.current_thread()),end="")

  在print打印字符串时就打印'\n'换行符,因为字符串是不可变类型,它可以作为一个整体不被分割输出。

2、logging模块

logging模块是分级别输出,不允许被打断,是安全的。

import threading
import time
import logging
logging.basicConfig(level=logging.INFO) #警告级别 def worker():
for x in range(100):
# time.sleep(0.5)
msg = ("{} is running".format(threading.current_thread()))
logging.info(msg) for i in range(1):
t = threading.Thread(target=worker,name='worker-{}'.format(i))
t.start() 运行结果:
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
INFO:root:<Thread(worker-0, started 123145503371264)> is running
......

  关于logging模块下一篇详细介绍。

daemon线程与non-daemon线程:

进程靠线程执行代码,一个进程至少有一个主线程,其它线程都是工作线程。

主线程是第一个启动的线程。

父线程:如果线程A启动了一个线程B,A就是B的父线程。

子线程:B就是A的子线程。

daemon属性要在start()方法之前设置。

daemon=None 或者不设置时,  等同于父线程的daemon的值

daemon=True   父线程退出该线程也退出

daemon=False  父线程必须等该线程执行完毕。

class Thread:
def __init__(self, group=None, target=None, name=None,
args=(), kwargs=None, *, daemon=None):   if daemon is not None:
   self._daemonic = daemon
   else:
   self._daemonic = current_thread().daemon #默认False

  Python在构造线程时,daemon参数接收值为True或False,默认为None时,等同于父线程的daemon值。

举例:

import threading
import time
import logging
logging.basicConfig(level=logging.INFO) #警告级别 def worker():
for x in range(100):
time.sleep(1)
msg = ("{} is running".format(threading.current_thread()))
logging.info(msg) t = threading.Thread(target=worker,name='worker-{}'.format(0),daemon=True)
t.start() time.sleep(3)
print('ending') 运行结果:
INFO:root:<Thread(worker-0, started daemon 123145520332800)> is running
INFO:root:<Thread(worker-0, started daemon 123145520332800)> is running
ending

  daemon属性为True时,主线程在启动子线程后,继续执行之后语句,主线程执行完毕后,自动退出了所有子线程,主线程也退出。也就是说,当daemon为True时,主线程结束时,子线程无论是否有任务未完成都会随着主线程一起退出。

  当daemon为False时也叫non-daemon,主线程运行完毕后,如果有子线程没有退出,就会等待子线程执行完毕,才会退出主线程,整个程序也就结束了。

嵌套的daemon线程:

import threading
import logging
logging.basicConfig(level=logging.INFO) #警告级别
import time def worker():
for x in range(10):
time.sleep(0.3)
msg = ("{} {} is running".format(x,threading.current_thread()))
logging.info(msg) #worker不等worker1
t = threading.Thread(target=worker1,name="worker1-{}".format(x),daemon=True)
t.start()
print(x,'~~~~~~~~~~~~~~~~~~~~~')
# t.join() def worker1():
for x in range(1000):
time.sleep(0.3)
msg = ("¥¥¥¥¥{} is running".format(threading.current_thread()))
logging.info(msg) t = threading.Thread(target=worker,name='worker-{}'.format(0),daemon=False) #主线程等待worker
t.start() # 主 子 孙
# t.join() # False False True
time.sleep(1)
print('ending')
print(threading.enumerate())

  这里很容易绕晕,直接看结论把。

小结:

主线程    子线程    子子线程

False      False      True

主线程

启动子线程

子进程也启动子线程

  

再傻瓜点理解就是层次最深的线程的daemon影响整个程序的执行结果,如果没有设置daemon,则取它的父线程的daemon。 下一篇详细介绍。

小结:

non-daemon (False) 主线程会等待非daemon线程执行完毕才退出,所以工作完整性请使用non-daemon线程。

daemon (True) 主线程结束,子线程也会结束。适用于不关心什么时候启动,什么时候结束,丢失一部分数据也不关心的场景。例如:服务、心跳包、监控场景应用居多。

join()方法:

正常场景,主线程在起了一个新的子线程后,主线程和子线程是并行的,互不干扰。但是,假如主线程调用了join方法,那它就得等待子线程完全执行完毕才能执行join()之后的语句,相当于又变成了单线程按顺序执行。

举例:

import threading
import time def worker():
for i in range(5):
time.sleep(0.5)
print('working....') t = threading.Thread(target=worker)
t.start()
# t.join() #没有使用join()时的运行情况
print('ending.') 运行结果:
ending.
working....
working....
working....
working....
working....

  上面例子中,先打印了主线程的“ending.”语句,说明没有使用join()方法时,主线程线运行完毕,等待子线程也运行完毕才退出程序。

import threading
import time def worker():
for i in range(5):
time.sleep(0.5)
print('working....') t = threading.Thread(target=worker)
t.start()
t.join() #使用join()方法时
print('ending.') 运行结果:
working....
working....
working....
working....
working....
ending.

  上面例子中,程序先打印的是子线程的语句,子线程运行完毕后,才打印了主线程的“ending.”语句,也就是使用了join()方法后,又变成了面向过程的程序,后一个语句必须要等前一个语句执行完毕才能执行。

  

Python 多线程 线程安全、daemon简介 (四)的更多相关文章

  1. 说说Python多线程中的daemon属性方法

    大家看多线程部分的时候肯定看到过daemon这个属性,当我在百度了一圈后也没发现有比较好的解释(或者大家对这个解释都非常清楚),于是自己通过代码和官方介绍了解它,进行了一些总结 给大家一些参考. 首先 ...

  2. [Python 多线程] 详解daemon属性值None,False,True的区别 (五)

    本文以多个例子介绍Python多线程中daemon属性值的区别. 回顾: 前面的文章简单介绍了在现代操作系统中,每一个进程都认为自己独占所有的计算机资源. 或者说线程就是独立的王国,进程间是相对独立的 ...

  3. python多线程--线程同步

    如果多个线程共同对某个数据修改,则可能出现不可预料的结果,为了保证数据的正确性,需要对多个线程进行同步. 使用Thread对象的Lock和Rlock可以实现简单的线程同步,这两个对象都有acquire ...

  4. Python多线程-线程锁

    多线程修改一份数据时需要用到线程锁,以防止数据修改出错 #-*- coding:utf-8 -*- __author__ = "MuT6 Sch01aR" import threa ...

  5. Python多线程,线程死锁及解决,生产者与消费者问题

    1.Thread类 普通调用 t = Thread(target=test, args=(i,)) # test为目标函数名, 若函数需要参数将其以元组形 # 式赋给args, 若无参数可不写 t.s ...

  6. Python数据分析Numpy库方法简介(四)

    Numpy的相关概念2 副本和视图 副本:复制 三种情况属于浅copy 赋值运算 切片 视图:链接,操作数组是,返回的不是副本就是视图 c =a.view().创建a的视图/影子和切片一样都是浅cop ...

  7. Python多线程多进程那些事儿看这篇就够了~~

    自己以前也写过多线程,发现都是零零碎碎,这篇写写详细点,填一下GIL和Python多线程多进程的坑~ 总结下GIL的坑和python多线程多进程分别应用场景(IO密集.计算密集)以及具体实现的代码模块 ...

  8. Java 多线程(四)之守护线程(Daemon)

    目录 定义 如何创建 判断 注意事项 函数setDaemon(true)必须在 start() 函数之前使用. 守护线程中产生的线程也是守护线程: 测试 @ 定义 Java 中有两种线程: 一种是用户 ...

  9. 进程,线程,GIL,Python多线程,生产者消费者模型都是什么鬼

    1. 操作系统基本知识,进程,线程 CPU是计算机的核心,承担了所有的计算任务: 操作系统是计算机的管理者,它负责任务的调度.资源的分配和管理,统领整个计算机硬件:那么操作系统是如何进行任务调度的呢? ...

随机推荐

  1. MySQL Community Server 5.5.56 ZIP Archive 绿色解压版 window安装步骤

    MySQL Community Server 5.5.56  ZIP Archive  绿色解压版 window安装步骤 首先 准备好启动配置文件my.ini [mysqld] #设置字符集为utf8 ...

  2. 中南月赛 B题 Scoop water

    Problem B: Scoop water Time Limit: 2 Sec  Memory Limit: 128 MBSubmit: 261  Solved: 57[Submit][Status ...

  3. shutil的一些基本用法

    import shutil import time import tarfile # 将文件内容拷贝到另一个文件中 shutil.copyfileobj(open('a1', 'r'), open(' ...

  4. JavaScript & jQuery & Bootstrap

    一.前言 javascript 简称 JS  与java编程语言 没有什么关系 JavaScript: {核心(ECMAScript) 文档对象模型(DOM) Document object mode ...

  5. 原型链继承中的prototype、__proto__和constructor的关系

    前不久写了有关原型链中prototype.__proto__和constructor的关系的理解,这篇文章说说在原型链继承中的prototype.__proto__和constructor的关系. 通 ...

  6. 爬虫必备—requests

    Requests 是使用 Apache2 Licensed 许可证的 基于Python开发的HTTP 库,其在Python内置模块的基础上进行了高度的封装,从而使得Pythoner进行网络请求时,变得 ...

  7. 【vue入门】日志demo,增删改查的练习(无vuex版本)

    安装 1. 确定电脑已装node和npm 出现版本号则说明电脑已经安装好node和npm2. 创建一个基于webpack的项目   3. 在项目里安装依赖 4. 运行 配置路由为了动态渲染各个页面的组 ...

  8. 英文版win10更新以后, 中文软件变成乱码

    原因是非Unicode程序的语言设置失效了 在区域设置里把当前系统区域设置改成"英语(美国)", 重启电脑后再改回"中文(简体, 中国)", 再重启就好了.

  9. [iOS] UIFont 设置字体

    label.font = [UIFont fontWithName:@"Arial-BoldItalicMT" size:24]; 字体名如下: Font Family: Amer ...

  10. MUI框架-01-介绍-创建项目-简单页面

    MUI框架-01-介绍-准备-创建项目 从0开始快速高效学习 MUI 框架 官方文档:http://dev.dcloud.net.cn/mui/ui/ (1)MUI 介绍 MUI 是什么,解决了什么问 ...