day 7-6 多线程及开启方式
一. 什么是线程
线程:顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程
所以,进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。
多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。(一个进程里面开多个线程(共享同一个进程里面的内存空间))
例如,北京地铁与上海地铁是不同的进程,而北京地铁里的13号线是一个线程,北京地铁所有的线路共享北京地铁所有的资源,比如所有的乘客可以被所有线路拉。
注意:
1.所以进程里面真正干活的是线程(进程里面有线程)
2.进程只是用来把资源互相隔离开,而线程才是真正负责cpu来调动他的
二. 线程的创建开销小
创建进程的开销要远大于线程?
如果我们的软件是一个工厂,该工厂有多条流水线,流水线工作需要电源,电源只有一个即cpu(单核cpu)
一个车间就是一个进程,一个车间至少一条流水线(一个进程至少一个线程)
创建一个进程,就是创建一个车间(申请空间,在该空间内建至少一条流水线)
而建线程,就只是在一个车间内造一条流水线,无需申请空间,所以创建开销小
三. 线程与进程的区别
1.创建线程比进程开销小(开一个进程,里面就有空间了,而线程在进程里面,就没必要在开一个空间了)
2.多线程一定是在一个进程里面开启的,共享进程里面的资源
3.线程启动的速度快
4.同一进程下的多个线程共享进程的资源,而多个进程之间内存空间是隔离的
如果开进程n是相互独立的,而线程是共享了资源,就不隔离了
在wins下开进程,子进程不会拷贝父进程的
在linux下开进程,子进程会完全拷贝父进程的
5.线程可以跟它所在的进程之内 的线程通信
四. 为何要用到多线程
多线程指的是,在一个进程中开启多个线程,简单的讲:如果多个任务共用一块地址空间,那么必须在一个进程内开启多个线程。详细的讲分为4点:
1. 多线程共享一个进程的地址空间
2. 线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用
3. 若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。
4. 在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)
五. 开启线程的方式
from threading import Thread
import time
import random def task(name):
print("%s is running"%name)
time.sleep(random.randint(1,3))
print("%s is done"%name)
if __name__ == '__main__':
t1 = Thread(target=task,args=("线程",))
t1.start()
print("主进程....")
开线程方式一
from threading import Thread
import time
import random class Mythread(Thread):
def __init__(self,name):
super().__init__()
self.name = name def run(self):
print("%s is running"%self.name)
time.sleep(random.randint(1,3))
print("%s is done"%self.name) if __name__ == '__main__':
t1 =Mythread("子线程")
t1.start()
print("主线程")
开线程方式二(类方法)
注意:主进程开启后,默认会有一个线程,当运行t1子线程的时候,进程内是有2个线程的.
六. 线程和进程的开启区别
注意:线程间是平等的,并无子线程的概念.
#1. 线程的开启速度要比进程快 from multiprocessing import Process
from threading import Thread
import time def task(name):
print("%s is running" %name)
time.sleep(2)
print("%s is done" % name) if __name__ == '__main__':
# p=Process(target=task,args=("进程1",))
# p.start()
# print("主进程") # 进程开启速度慢,开销大,所以向系统发出开进程的请求后,并不会立刻开启一个进程,才会先输出 "主进程",然后才能看到进程1的运行
t = Thread(target=task,args=("线程1",))
t.start()
print("主进程") # 线程开启速度快,开销小.发送开线程请求后,立刻就能开启.在线程sleep的时候,才运行"主进程"
线程和进程的开启开销
# 2 线程和进程的数据不同
from multiprocessing import Process
from threading import Thread
import time
import os
n=50
def task(name):
global n
n = 100
print("task",n) if __name__ == '__main__':
p=Process(target=task,args=("进程1",))
p.start()
print("主进程",n) # 进程间的数据是隔离的,所以主进程还是50,进程p更改了n=100,所以task的n等于100
# t = Thread(target=task,args=("线程1",))
# t.start()
# print("主线程",n) # 线程之间的数据是共享的.线程t开启后,更改了n的值,因为数据是共享的,所以主线程的n也是100
数据共享方式不同
#3. pid不同 from multiprocessing import Process
from threading import Thread
import time
import os
def task(name):
# print(os.getpid())
print(os.getpid(),os.getppid()) # 查看当前进程和父进程的pid if __name__ == '__main__':
p=Process(target=task,args=("进程1",))
p.start()
print("主进程",os.getpid()) #2个进程,有2个不同的pid
# t = Thread(target=task,args=("线程1",))
# t.start()
# print("主线程",os.getpid())
Pid不同
七. 线程的其他方法和属性
from threading import Thread,currentThread,active_count,enumerate
import time def task():
print("%s is running"%currentThread().getName()) #获取当前线程的名字
time.sleep(2)
print("%s is done"%currentThread().getName()) if __name__ == '__main__':
t = Thread(target=task,name="线程1")
t.start()
t.setName("更改后的线程名") # 输入到控制台的时候,我们会发现,running和done的名字不一样.是因为线程start后,就立刻开启了,用的名字还是"线程1",在线程1sleep
#的时候,setname才完成更改,所以后面的done线程名和之前的不一样
t.join() # 等待线程1执行完毕
print(t.is_alive()) # 查看线程是否存活,2种方法
print(t.isAlive())
currentThread().setName("我的主线程") # 更改主线程的名字
print("主线程:%s"%currentThread().getName())
print(active_count()) #查看线程数量
print(enumerate()) # 查看具体的线程对象,active_count方法就是len(enumerate())的结果
八. 多线程互斥锁
我们知道线程之间的数据是共享的,如果同时开启多个线程对同一个数据进行修改,那么发生什么样的事情呢?
from threading import Thread,Lock
import time n =100
def task():
global n
temp = n
time.sleep(0.1)
n = temp-1 if __name__ == '__main__':
temp_li=[]
for i in range(3):
t1 = Thread(target=task)
t1.start()
temp_li.append(t1) for t in temp_li:
t.join() print("main",n)
-----------------------------------------------------------------------------------------
main 99
最后输出的是99.为什么不是97呢?我们循环三次,开启3个线,当第一个线程运行到sleep的时候,其他线程也都运行到sleep这里了.这时候3个线程拿到的n的值都是100,所以等sleep结束后,每个线程都做了一次100-1的操作.所以最后的n就等于99了.可是这不是我们想要的结果,我们想要的是:每运行一次,n就减去1.这个时候就应该用到互斥锁了.
from threading import Thread,Lock
import time n =100
def task(mutex):
global n
mutex.acquire()
temp = n
time.sleep(0.1)
n = temp-1
mutex.release() if __name__ == '__main__':
mutex = Lock()
temp_li=[]
for i in range(3):
t1 = Thread(target=task,args=(mutex,))
t1.start()
temp_li.append(t1) for t in temp_li:
t.join() print("main",n)
-----------------------------------------------------------------------------------------
main 97
加上互斥锁之后,最后的n就成了97.不加互斥锁的程序运行效率比加了锁的要高.但是数据不安全,因为不加锁是并发执行的,加锁后,变成了串行执行,效率低.数据安全.
day 7-6 多线程及开启方式的更多相关文章
- 多线程的实现方式01 Thread
/* * 多线程 有三种实现方式 * 其一 Thread * * 写一个类 * * 1.让他继承 Thread * 2.重写thread中的run方法 * 3.创建子类对象就是在 创建线程! * 3. ...
- 牛客网Java刷题知识点之什么是进程、什么是线程、什么是多线程、多线程的好处和弊端、多线程的创建方式、JVM中的多线程解析、多线程运行图解
不多说,直接上干货! 什么是进程? 正在进行中的程序(直译). 什么是线程? 就是进程中一个负责程序执行的控制单元(执行路径). 见 牛客网Java刷题知识点之进程和线程的区别 什么是多线程? 一个进 ...
- 安卓服务(Service)的两种开启方式以及服务的生命周期
安卓中服务的开启方式 一:採用start的方式开启服务 调用函数:startService(Intent)->onCreate()->onStart()/onStartCommand()- ...
- python并发编程之多进程(一):进程开启方式&多进程
一,进程的开启方式 利用模块开启进程 from multiprocessing import Process import time,random import os def piao(name): ...
- 性能优化之mysql优化——慢查日志的开启方式和存储
-- MySQL优化 -- mysql 慢查日志的开启方式和存储 -- 1) 查看mysql是否开启慢查询日志 SHOW VARIABLES LIKE 'slow_query_log'; -- 2) ...
- python开发进程:进程开启方式&多进程
一,进程的开启方式 利用模块开启进程 from multiprocessing import Process import time,random import os def piao(name): ...
- java——多线程的实现方式、三种办法解决线程赛跑、多线程数据同步(synchronized)、死锁
多线程的实现方式:demo1.demo2 demo1:继承Thread类,重写run()方法 package thread_test; public class ThreadDemo1 extends ...
- canvas之webgl的浏览器开启方式
引自百度知道的回答 1.开启方式: 第一种:打开cmd,切换到Chorme的安装目录,敲入chrome.exe --enable -webgl,回车就会打开一个chrome浏览器窗口: 第二种:找到C ...
- Java中的多线程的创建方式
首先理清几个基本概念: 程序:为完成特定任务,用某种语言编写的一组指令的集合.即一段静态的代码(还没运行起来) 进程:是程序的一次执行过程,也就是说程序运行起来了,加载到了内存中,并占用了cpu的资源 ...
随机推荐
- EBS採购模块中的高速接收和高速接收事务
EBS採购模块中的高速接收和高速接收事务 (版权声明.本人原创或者翻译的文章如需转载,如转载用于个人学习,请注明出处.否则请与本人联系,违者必究) 高速功能是一个高速输入收货和接收事务的方法. 在收货 ...
- D. Diverse Garland
题意:灯有三种颜色R,G,B.只要同一种颜色相邻就不可以.问最少需要换几次,可以使在一串灯中没有相邻灯的颜色相同. 思路:贪心思路:我们知道一个程序都是要子阶段,然后子阶段各个组合起来形成这个程序.那 ...
- nginx服务器下 PHP 出现 502 解决方案
https://blog.csdn.net/qq_34625397/article/details/51744859 nginx出现502有很多原因,但大部分原因可以归结为资源数量不够用,也就是说后端 ...
- 8.oop-多态
一.继承1.定义:子类继承父类,会继承父类的属性和方法2.语法:extends关键字 子类 extends 父类3.特点:java中的继承是单一继承,子类只能继承一个父类,但是父类可以有多个子类4.用 ...
- 数据泵expdp 在rac环境下 paralle 的处理方法
其实这个是个很常见的问题,写下来做纪念吧.说明:而在11GR2后EXPDP 和 IMDP的WORKER进程在设置parallel参数时会在多个INSTANCE启动,所以DIRECTORY必须在共享磁盘 ...
- Python 中的浅拷贝和深拷贝
1. 列表和字典,直接赋值,都是浅拷贝,即赋值双方指向同一地址,因为 Python 对可变对象按引用传递. >>> a = [1, 2, 3] >>> b = a ...
- CF176E Archaeology
CF176E Archaeology 有一棵 \(n\) 个点的带权树,每个点都是黑色或白色,最初所有点都是白色的.有 \(m\) 个询问: 把点 \(x\) 从白色变成黑色 把点 \(x\) 从黑色 ...
- Linux—日志查看(测试人员)
备注:在筛选语句后面加“--col”可以高亮显示查询结果中的关键字 cd /home/admin/logs/服务器名 #进入日志目录(错误日志文件:common-error.log),路径因公司而定 ...
- 初学Python——列表生成式、生成器和迭代器
一.列表生成式 假如现在有这样一个需求:快速生成一个列表[1,2,3,4,5,6,7,8,9,10],该如何实现? 在不知道列表生成式的情况下,可能会这样写: a=[1,2,3,4,5,6,7,8,9 ...
- mac sourcetree push分支选中所有tag的时候报错
错误信息: ....... ! [rejected] 573_0811_stable -> 573_0811_stable (already exists)updating local trac ...