理论部分

一、什么是线程:

1.线程:一条流水线的工作过程 

2.一个进程里至少有一个线程,这个线程叫主线程

  进程里真正干活的就是线程

3.进程只是用来把资源集中到一起(进程只是一个资源单位,或者说资源集合),而线程才是cpu上的执行单位。

4.多线程(即多个控制线程)的概念是,在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间,相当于一个车间内有多条流水线,都共用一个车间的资源。

  共享就存在竞争,----加锁-----队列

 from multiprocessing import Process
from threading import Thread
import os
import time
n=100
def work():
global n
n-=100 if __name__ == '__main__':
p=Thread(target=work,)
p.start()
p.join()
print('主',n) #结果是0

二、线程的创建开销小,因而创建线程的速度快

 from multiprocessing import Process
from threading import Thread
import os
import time
def work():
print('<%s> is running' %os.getpid())
time.sleep(2)
print('<%s> is done' %os.getpid()) if __name__ == '__main__':
t=Thread(target=work,)
t.start()
print('主',os.getpid()) 结果:
<20348> is running
主 20348
<20348> is done

1.进程之间内存空间是互相隔离的

三、线程与进程的区别

  1.线程共享创建它的进程的地址空间;进程有自己的地址空间。

  2.线程可以直接访问其进程的数据段;进程有自己的父进程数据段的副本。(Linux系统,Windows系统也可以这么说,但是要注意Windows没有子进程的概念)

  3.线程可以与进程的其他线程直接通信;进程必须使用进程间通信来与同级进程通信。

  4.新线程很容易创建;新进程需要父进程的重复。

总之记住两点就ok: 1、多线程共享它们进程的资源,2、线程的创建开销小

 from multiprocessing import Process
from threading import Thread
import os
import time
n=100
def work():
global n
n-=100 if __name__ == '__main__':
# p=Process(target=work,)
p=Thread(target=work,)
p.start()
p.join()
print('主',n)

  5.扩展:分布式与集中式(所有的东西放在一起)

四、为什么实用多线程:

  1、多线程共享它们进程的资源,2、线程的创建开销小

五、多线程的应用举例

  开启一个字处理软件进程,该进程肯定需要办不止一件事情,比如监听键盘输入,处理文字,定时自动将文字保存到硬盘,这三个任务操作的都是同一块数据,因而不能用多进程。只能在一个进程里并发地开启三个线程,如果是单线程,那就只能是,键盘输入时,不能处理文字和自动保存,自动保存时又不能输入和处理文字。 

 

代码部分

六、开启进程的两种方式:

 #方式一
from threading import Thread
import time
def sayhi(name):
time.sleep(2)
print('%s say hello' %name) if __name__ == '__main__':
t=Thread(target=sayhi,args=('egon',))
t.start()
print('主线程')

方式一

 #方式二
from threading import Thread
import time
class Sayhi(Thread):
def __init__(self,name):
super().__init__()
self.name=name
def run(self):
time.sleep(2)
print('%s say hello' % self.name) if __name__ == '__main__':
t = Sayhi('egon')
t.start()
print('主线程')

方式二

七、多线程共享同一个进程内的地址空间

  多线程共享——>竞争——>锁

八、练习

from socket import *
from threading import Thread
s=socket(AF_INET,SOCK_STREAM)
s.setsockopt(SOL_SOCKET,SO_REUSEADDR,1)
s.bind(('192.168.20.95',8082))
s.listen(5)
def talk(conn):
while True:
try:
cmd=conn.recv(1024)
if not cmd:break
conn.send(cmd.upper())
except Exception:
break
conn.close() if __name__ == '__main__':
while True:
conn,addr=s.accept()
p=Thread(target=talk,args=(conn,))
p.start()
s.close()

多线程并发的socket服务端

 from socket import *
c=socket(AF_INET,SOCK_STREAM)
c.connect(('192.168.20.95',8082)) while True:
msg=input('>>: ').strip()
if not msg:continue
c.send(msg.encode('utf-8'))
data=c.recv(1024)
print(data.decode('utf-8'))
c.close()

客户端

练习二:三个任务,一个接收用户输入,一个将用户输入的内容格式化成大写,一个将格式化后的结果存入文件

 from threading import Thread
input_l=[]
format_l=[]
def talk():
while True:
msg=input('>>: ')
if not msg:continue
input_l.append(msg)
def format():
while True:
if input_l:
res=input_l.pop()
format_l.append(res.upper())
def save():
with open('db.txt','a') as f:
while True:
if format_l:
f.write('%s\n' %(format_l.pop()))
f.flush() if __name__ == '__main__':
t1=Thread(target=talk)
t2=Thread(target=format)
t3=Thread(target=save) t1.start()
t2.start()
t3.start()

九、线程相关的其他属性及方法(了解)

 Thread实例对象的方法
# isAlive(): 返回线程是否活动的。
# getName(): 返回线程名。
# setName(): 设置线程名。 threading模块提供的一些方法:
# threading.currentThread(): 返回当前的线程变量。
# threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程。
# threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果。
 from threading import Thread,currentThread,activeCount
import os,time,threading
def talk():
print('%s is running' %currentThread().getName()) if __name__ == '__main__':
# t=Thread(target=talk,name='egon')
t=Thread(target=talk)
t.start()
print(t.name)
print(t.getName())
print(t.is_alive())
print(currentThread().getName())
print(threading.enumerate())
print('主',activeCount()) #结果
Thread-1 is running
Thread-1
Thread-1
False
MainThread
[<_MainThread(MainThread, started 33752)>]
主 1

十、守护进程

  进程: 主进程代码完——>守护死

  线程: 主线程的非守护线程完——>守护死

十一、全局解释器锁:(GIL——CPython解释器的)

  1.保护系统级别的(CPython解释器)代码的安全,但是不能保护用户级别的数据(软件产生的代码)安全

  2.抢锁: 所有线程抢的是GIL锁,或者说所有线程抢的是执行权限

  3.释放锁: ①I/O阻塞  ②运行时间过长

  4.在一个进程中多个线程通过GIL就会变成串行的效果

  5.有了GIL的存在,同一时刻同一进程中只有一个线程被执行

  6.应用:

    多线程用于IO密集型,如socket,爬虫,web
    多进程用于计算密集型,如金融分析

十二、同步锁:

  GIL VS Lock

  过程分析:所有线程抢的是GIL锁,或者说所有线程抢的是执行权限

  线程1抢到GIL锁,拿到执行权限,开始执行,然后加了一把Lock,还没有执行完毕,即线程1还未释放Lock,有可能线程2抢到GIL锁,开始执行,执行过程中发现Lock还没有被线程1释放,于是线程2进入阻塞,被夺走执行权限,有可能线程1拿到GIL,然后正常执行到释放Lock。。。这就导致了串行运行的效果

  既然是串行,那我们执行

  t1.start()

  t1.join

  t2.start()

  t2.join()

  这也是串行执行啊,为何还要加Lock呢,需知join是等待t1所有的代码执行完,相当于锁住了t1的所有代码,而Lock只是锁住一部分操作共享数据的代码。

1 分析:
2   #1.100个线程去抢GIL锁,即抢执行权限
3 #2. 肯定有一个线程先抢到GIL(暂且称为线程1),然后开始执行,一旦执行就会拿到lock.acquire()
4 #3. 极有可能线程1还未运行完毕,就有另外一个线程2抢到GIL,然后开始运行,但线程2发现互斥锁lock还未被线程1释放,于是阻塞,被迫交出执行权限,即释放GIL
5 #4.直到线程1重新抢到GIL,开始从上次暂停的位置继续执行,直到正常释放互斥锁lock,然后其他的线程再重复2 3 4的过程

GIL锁与互斥锁综合分析(重点!!!)

练习:

 from threading import Thread,Lock
import time
n=100
def work():
mutex.acquire()
global n
temp=n
time.sleep(0.1)
n=temp-1
mutex.release() if __name__ == '__main__':
mutex=Lock()
t_l=[]
for i in range(100):
t=Thread(target=work)
t_l.append(t)
t.start()
for t in t_l:
t.join()
print(n)

  

    

python-day34--并发编程之多线程的更多相关文章

  1. python week08 并发编程之多线程--理论部分

    一. 什么是线程 1.定义 线程就像一条工厂车间里的流水线,一个车间里可以用很多流水线,来执行生产每个零部件的任务. 所以车间可以看作是进程,流水线可以看作是线程.(进程是资源单位,线程是执行单位) ...

  2. python week08 并发编程之多线程--实践部分

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

  3. Python并发编程04 /多线程、生产消费者模型、线程进程对比、线程的方法、线程join、守护线程、线程互斥锁

    Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线程join.守护线程.线程互斥锁 目录 Python并发编程04 /多线程.生产消费者模型.线程进程对比.线程的方法.线 ...

  4. python之并发编程

    一 背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象. 进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所 ...

  5. Python 3 并发编程多进程之队列(推荐使用)

    Python 3 并发编程多进程之队列(推荐使用) 进程彼此之间互相隔离,要实现进程间通信(IPC),multiprocessing模块支持两种形式:队列和管道,这两种方式都是使用消息传递的. 可以往 ...

  6. Python 3 并发编程多进程之进程同步(锁)

    Python 3 并发编程多进程之进程同步(锁) 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的,竞争带来的结果就是错乱,如何控制,就是加锁处理. 1. ...

  7. Python 3 并发编程多进程之守护进程

    Python 3 并发编程多进程之守护进程 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemo ...

  8. 使用Python进行并发编程

    让计算机程序并发的运行是一个经常被讨论的话题,今天我想讨论一下Python下的各种并发方式. 并发方式 线程(Thread) 多线程几乎是每一个程序猿在使用每一种语言时都会首先想到用于解决并发的工具( ...

  9. python中并发编程基础1

    并发编程基础概念 1.进程. 什么是进程? 正在运行的程序就是进程.程序只是代码. 什么是多道? 多道技术: 1.空间上的复用(内存).将内存分为几个部分,每个部分放入一个程序,这样同一时间在内存中就 ...

  10. python之并发编程初级篇8

    一.进程理论 1)进程介绍 .什么是进程 一个正在进行的过程,或者说是一个程序的运行过程 其实进程是对正在运行的程序的一种抽象/概括的说法 进程的概念起源操作系统,进程是操作最核心的概念之一 操作系统 ...

随机推荐

  1. MySQL Crash Course #14# Chapter 22. Using Views

    索引 视图是啥 为什么需要视图 使用视图的规则 如何使用视图 视图应用实例 别用视图更新数据! 视图是啥 理解视图的最佳方式就是看下面这个例子. SELECT cust_name, cust_cont ...

  2. Python入门之字典的操作详解

    这篇文章主要介绍了Python 字典(Dictionary)的详细操作方法,需要的朋友可以参考下: Python字典是另一种可变容器模型,且可存储任意类型对象,如字符串.数字.元组等其他容器模型. 一 ...

  3. c++ 11开始语言本身和标准库支持并发编程

    c++ 11开始语言本身和标准库支持并发编程,意味着真正要到编译器从语言和标准库层面开始稳定,估计得到17标准出来.14稳定之后的事情了,根据历史经验,新特性的引入到稳定被广泛采用至少要一个大版本的跨 ...

  4. 02: MySQL的安装与基本配置

    MySQL其他篇 目录: 参考网站 1.1 MySQL安装与基本配置(centos 7.3) 1.2 修改MySQL默认字符集和引擎 1.3 MySQL创建用户与授权 1.1 MySQL安装与基本配置 ...

  5. 基于qml创建最简单的图像处理程序(1)-基于qml创建界面

    <基于qml创建最简单的图像处理程序>系列课程及配套代码基于qml创建最简单的图像处理程序(1)-基于qml创建界面http://www.cnblogs.com/jsxyhelu/p/83 ...

  6. 20145101《Java程序设计》第三周学习总结

    20145101 <Java程序设计>第3周学习总结 教材学习内容总结 本周进行的是第四章和第五章的学习.本阶段的学习难度有所提升,无论是在知识的量还是深度都开始增加,内容很丰富,也很有趣 ...

  7. 20145104张家明 《Java程序设计》第9周学习总结

    20145104张家明 <Java程序设计>第9周学习总结 教材学习内容总结 第16章 -撰写应用程序是利用通信协议对数据库进行指令交换,以进行数据的增删查找. -JDBC目的:让Java ...

  8. 网络安全、Web安全、渗透测试之笔经面经总结(三)

    本篇文章涉及的知识点有如下几方面: 1.什么是WebShell? 2.什么是网络钓鱼? 3.你获取网络安全知识途径有哪些? 4.什么是CC攻击? 5.Web服务器被入侵后,怎样进行排查? 6.dll文 ...

  9. 如何去除 gvim 的 acp和 "option omnifunc is not set" 的问题

    "option omnifunc is not set" 的问题, 确实是困扰了很久的问题! 首先, 在vim中,自动完成是通过两个文件来实现的, 自动完成, 就是 acp: = ...

  10. Java8中数据流的使用

    Code: @Data @ToString @NoArgsConstructor @AllArgsConstructor public class Employee { private Integer ...