并发编程之多线程

一、并发编程之多线程

1、线程简单介绍

进程是资源单位,把所有资源集中到一起,而线程是执行单位,真正执行的是线程

每个进程都有一个地址空间,而且默认就有一个控制线程

多线程:在一个进程中存在多个控制线程,多个控制线程共享该进程的地址空间。进程之间是竞争关系,线程之间是协作关系

线程的创建开销比进程小很多,运行较快

主线程从执行层面上代表了其所在进程的执行过程

2、线程开启方式

方式一:使用替换threading模块提供的Thread

from threading import Thread
 
 def task():
   print(‘is running‘)

if __name__ == ‘__main__‘:
   t=Thread(target=task,)
   t.start()
   print(‘主‘)

方式二:自定义类,继承Thread

from threading import Thread
class MyThread(Thread):
  def __init__(self,name):
    super().__init__()
    self.name=name
  def run(self):
    print(‘%s is running‘ %self.name)

if __name__ == ‘__main__‘:
  t=MyThread(‘egon‘)
  t.start()
  print(‘主‘)

3、线程与进程的pid

from threading import Thread
from multiprocessing import Process
import os

def task():
  print(‘%s is running‘ %os.getpid())

if __name__ == ‘__main__‘:
  # t1=Thread(target=task,)      #在主进程下开启多个线程,每个线程都跟主进程的pid一样
  # t2=Thread(target=task,)
  t1=Process(target=task,)     #开启多个进程,每个进程都有不同的pid
  t2=Process(target=task,)
  t1.start()
  t2.start()
  print(‘主‘,os.getpid())

4、多线程共享同一个进程内的资源

from threading import Thread
from multiprocessing import Process
n=100
def work():
  global n
  n=0

if __name__ == ‘__main__‘:

  # p=Process(target=work,)        
  # p.start()
  # p.join()
  # print(‘主‘,n)                 #子进程p已经将自己的全局的n改成了0,但改的是它自己的,父进程仍然是100

  t=Thread(target=work,)
  t.start()
  t.join()
  print(‘主‘,n)                    #查看结果为0,同一进程内的线程之间共享进程内的数据

5、Thread对象其他相关的属性或方法

isAlive():返回线程是否活动

getName():返回线程名

setName():设置线程名

current_thread的用法
 from threading import Thread,activeCount,enumerate,current_thread
 from multiprocessing import Process
 import time

def task():
   print(‘%s is running‘ %current_thread().getName())
   time.sleep(2)

if __name__ == ‘__main__‘:
   p=Process(target=task)
   p.start()
   print(current_thread())

6、守护线程

进程跟线程都会遵循:守护xxx会等待主xxx运行完毕后被销毁

主进程:运行完毕指的是主进程代码运行完毕

主线程:运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕

注意:运行完毕并非终止运行

from threading import Thread
import time

def task1():
  print(‘123‘)
  time.sleep(10)
  print(‘123done‘)

def task2():
  print(‘456‘)
  time.sleep(1)
  print(‘456done‘)

if __name__ == ‘__main__‘:
  t1=Thread(target=task1)
  t2=Thread(target=task2)
  t1.daemon=True
  t1.start()
  t2.start()
  print(‘主‘)

7、GIL全局解释器锁

GIL本质是一把互斥锁,将并发运行变成串行,以此来控制同一时间内共享数据只能被一个任务所修改,进而保证数据安全。

在Cpython解释器中,同一个进程下开启的多线程,同一时刻只能有一个线程执行,无法利用多核优势

from threading import Thread
n=100
  def task():
    print(‘is running‘)

if __name__ == ‘__main__‘:
  t1=Thread(target=task,)
  t2=Thread(target=task,)
  t3=Thread(target=task,)
  # t=Process(target=task,)
  t1.start()
  t2.start()
  t3.start()
  print(‘主‘)

多个线程先访问到解释器的代码,即拿到执行权限,然后将target的代码交给解释器的代码去执行

解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:对于同一个数据100,可能线程1执行n=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理,如下图的GIL,保证python解释器同一时间只能执行一个任务的代码

结论:

1、如果是I/O密集型的,可以开启多线程

2、如果是要求计算性能,可以利用多核,开启进程

8、同步锁

1、线程抢的是CIL锁,GIL锁相当于执行权限,拿到执行权限后才能拿到互斥锁lock,其他线程也可以抢到GIL,但如果发现lock仍然没有被释放则阻塞,即便是拿到执行权限GIL也要立刻交出来

2、jion是等待所有,即整体串行,而锁只是锁住修改共享数据的部分,即部分串行,要想保住数据安全性的根本原来在于让并发变成串行,jion与互斥锁都可以实现,互斥锁的部分串行效率更高

时间: 2024-12-16 08:59:54

并发编程之多线程的相关文章

day10-python并发编程之多线程协程及MySQL

第1章 python并发编程之多线程 1.1 死锁现象与递归锁 1.1.1 死锁概念 进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁 1.1.2 博客实例 from threading import Thread,Lock import time mutexA=L

python 学习_第四模块 并发编程(多线程)

python 学习_第四模块 并发编程(多线程) 1  开启线程方式 from threading import Thread import time def say(name): time.sleep(2) print("%s hello"%name) if __name__ =="__main__": t = Thread(target=say,args=("alex",)) t.start() print("主线程")

Python并发编程04/多线程

目录 Python并发编程04/多线程 1.生产消费者模型 2.线程的理论知识 2.1什么是线程 2.2线程vs进程 2.3线程的应用 3.开启进程的两种方式 3.1第一种方式 3.2第一种方式 4.线程vs进程的代码对比 4.1开启速度对比 4.2对比pid 4.3同一个进程内线程共享内部数据 5.线程的其他方法 6.join与守护线程 6.1join 6.2守护线程 7.互斥锁 Python并发编程04/多线程 1.生产消费者模型 #编程思想,模型,设计模式,理论等等,都是交给你一种编程的方

Java并发编程之多线程同步

线程安全就是防止某个对象或者值在多个线程中被修改而导致的数据不一致问题,因此我们就需要通过同步机制保证在同一时刻只有一个线程能够访问到该对象或数据,修改数据完毕之后,再将最新数据同步到主存中,使得其他线程都能够得到这个最新数据.下面我们就来了解Java一些基本的同步机制. Java提供了一种稍弱的同步机制即volatile变量,用来确保将变量的更新操作通知到其他线程.当把变量声明为volatile类型后,编译器与运行时都会注意到这个变量是共享的.然而,在访问volatile变量时不会执行加锁操作

Java并发编程、多线程、线程池…

Java多线程干货系列(1):Java多线程基础http://www.importnew.com/21136.html#comment-651146 40个Java多线程问题总结http://www.importnew.com/18459.html#comment-651217 Java线程面试题 Top 50http://www.importnew.com/12773.html Java并发编程:Thread类的使用http://www.cnblogs.com/dolphin0520/p/39

【并发编程】多线程程序同步策略

目录 C++11线程使用初探 采用条件变量等待某个事件或条件发生 线程安全的队列适配器 C++11线程使用初探 std::thread #include <thread> 只读的共享数据在多个线程间不存在Race condition的危险,而可读可写共享数据在线程间共享时则需做好线程同步,即数据保护,主要包括lock-based和lock-free策略. 常见的以互斥锁保护多线程间的共享数据,保证某一时刻仅有一个线程访问共享数据,导致线程间数据保护是串行,因此在多线程环境中,锁保护的区域越小,

python并发编程之多线程理论部分

阅读目录 一 什么是线程 二 线程的创建开销小 三 线程与进程的区别 四 为何要用多线程 五 多线程的应用举例 六 经典的线程模型(了解) 七 POSIX线程(了解) 八 在用户空间实现的线程(了解) 九 在内核空间实现的线程(了解) 十 用户级与内核级线程的对比(了解) 十一 混合实现(了解) 一 什么是线程 在传统操作系统中,每个进程有一个地址空间,而且默认就有一个控制线程 线程顾名思义,就是一条流水线工作的过程,一条流水线必须属于一个车间,一个车间的工作过程是一个进程 车间负责把资源整合到

百万年薪python之路 -- 并发编程之 多线程 一

多线程 1.进程: 生产者消费者模型 一种编程思想,模型,设计模式,理论等等,都是交给你一种编程的方法,以后遇到类似的情况,套用即可 生产者与消费者模型的三要素: 生产者:产生数据的 消费者:接收数据做进一步处理的 容器: 缓存区(队列) 起到缓冲的作用,平衡生产力与消费者,解耦 2.线程的理论知识 什么是线程 一条流水线的工作流程 进程: 在内存中开启一个进程空间,然后将主进程的所有的资源复制一份,然后调用cpu去执行这些代码. 进程是资源调度的基本单位,而线程是cpu的最小执行单位 进程的开

python并发编程之多线程2------------死锁与递归锁,信号量等

一.死锁现象与递归锁 进程也是有死锁的 所谓死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用, 它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程, 如下就是死锁 1 死锁------------------- 2 from threading import Thread,Lock,RLock 3 import time 4 mutexA = Lock() 5 mutexB = Lock() 6