Day10-线程进程

什么是进程?

程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。

在多道编程中,我们允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,大大提高了CPU的利用率。进程的出现让每个用户感觉到自己独享CPU,因此,进程就是为了在CPU上实现多道编程而提出的。

有了进程为什么还要线程?

进程有很多优点,它提供了多道编程,让我们感觉我们每个人都拥有自己的CPU和其他资源,可以提高计算机的利用率。很多人就不理解了,既然进程这么优秀,为什么还要线程呢?其实,仔细观察就会发现进程还是有很多缺陷的,主要体现在两点上:

  • 进程只能在一个时间干一件事,如果想同时干两件事或多件事,进程就无能为力了。
  • 进程在执行的过程中如果阻塞,例如等待输入,整个进程就会挂起,即使进程中有些工作不依赖于输入的数据,也将无法执行。

例如,我们在使用qq聊天, qq做为一个独立进程如果同一时间只能干一件事,那他如何实现在同一时刻 即能监听键盘输入、又能监听其它人给你发的消息、同时还能把别人发的消息显示在屏幕上呢?你会说,操作系统不是有分时么?但我的亲,分时是指在不同进程间的分时呀, 即操作系统处理一会你的qq任务,又切换到word文档任务上了,每个cpu时间片分给你的qq程序时,你的qq还是只能同时干一件事呀。

再直白一点, 一个操作系统就像是一个工厂,工厂里面有很多个生产车间,不同的车间生产不同的产品,每个车间就相当于一个进程,且你的工厂又穷,供电不足,同一时间只能给一个车间供电,为了能让所有车间都能同时生产,你的工厂的电工只能给不同的车间分时供电,但是轮到你的qq车间时,发现只有一个干活的工人,结果生产效率极低,为了解决这个问题,应该怎么办呢?。。。。没错,你肯定想到了,就是多加几个工人,让几个人工人并行工作,这每个工人,就是线程!

什么是线程?

线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

进程线程总结:

进程:

  • 一个程序要运行时所需的所有资源的集合
  • 进程是资源的集合,相当于一个车间
  • 一个进程至少需要一个线程,这个线程称为主线程
  • 一个进程里可以有多个线程
  • cpu的核数越多,代表着可以真正并发的线程越多
  • 2个进程之间的数据是完全独立的,互相不能访问

线程:

  • 一道单一的指令的控制流,寄生在进程中
  • 单一进程里的多个线程是共享数据的
  • 多个线程在涉及修改同一个数据时一定要加锁

GIL

全局解释器锁,防止多个线程修改同一份数据

无论你启多少个线程,你有多少个cpu, Python在执行的时候会淡定的在同一时刻只允许一个线程运行

线程threading模块

启线程两种方式

直接调用

1、导入模块

2、定义函数

3、实际化threading.Thread

target跟函数名,args跟函数的参数,元祖,加逗号

import threading

def run(n):
    print(‘thread‘,n)

t = threading.Thread(target=run,args=(1,))
t.start()

启10个线程

import threading
import time

def run(n):
    time.sleep(1)
    print(‘thread‘,n)

for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()
print(t.getName())#线程名字print(threading.current_thread())#当前正在运行的线程的实例print(threading.active_count())#统计线程数

继承式调用

import threading
import time

class MyThread(threading.Thread):
    def __init__(self, num):
        threading.Thread.__init__(self)
        #super(MyThread, self).__init__()
        self.num = num

    def run(self):  # 定义每个线程要运行的函数
        print("running on number:%s" % self.num)
        time.sleep(3)

if __name__ == ‘__main__‘:
    t1 = MyThread(1)
    t2 = MyThread(2)
    t1.start()
    t2.start()

join&&Daemon

主线程等子线程全部走完再走

import threading
import time

def run(n):
    time.sleep(1)
    print(‘thread‘,n)
t_list = []
for i in range(10):
    t = threading.Thread(target=run,args=(i,))
    t.start()
    t_list.append(t)
for t in t_list:
    t.join()
print(‘main...‘)

#输出

thread 0
thread 1
thread 2
thread 3
thread 7
thread 8
thread 5
thread 4
thread 6
thread 9
main...

这里就是等10个子线程全部生成结束后执行主线程

Daemon

主线程挂了,子线程也一起挂啦

import  threading
import time

def run(n):
    time.sleep(1)
    print("thread",n)

for i in range(10):
    t = threading.Thread(target=run, args=(i,))
    t.setDaemon(True)#把子线程设置为主线程的守护线程
    t.start()

print("--main thread---")

#输出

--main thread---

线程锁(互斥锁Mutex)

一个进程下可以启动多个线程,多个线程共享父进程的内存空间,也就意味着每个线程可以访问同一份数据,此时,如果2个线程同时要修改同一份数据,会出现什么状况?可能数据会乱,python3中没问题,python2中有问题。

import threading
import time

def run(n):
    global num
    l.acquire()#获取锁
    num += 1
    l.release()#创建锁
    print(num)

num = 0
t_list = []
l = threading.Lock()#申明实例
for i in range(100):
    t = threading.Thread(target=run,args=(i,))
    t.start()
    t_list.append(t)
for i in t_list:
    i.join()
print(‘main‘)
print(num)

如果在num+=1后面加上time.sleep(1),就变成了串行,不要占着茅坑不拉屎,修改完数据后要立刻释放。对别的没有用到此修改数据的线程是没有关系的。

GIL VS Lock

那你又问了, 既然用户程序已经自己有锁了,那为什么C python还需要GIL呢?加入GIL主要的原因是为了降低程序的开发的复杂度,比如现在的你写python不需要关心内存回收的问题,因为Python解释器帮你自动定期进行内存回收,你可以理解为python解释器里有一个独立的线程,每过一段时间它起wake up做一次全局轮询看看哪些内存数据是可以被清空的,此时你自己的程序 里的线程和 py解释器自己的线程是并发运行的,假设你的线程删除了一个变量,py解释器的垃圾回收线程在清空这个变量的过程中的clearing时刻,可能一个其它线程正好又重新给这个还没来及得清空的内存空间赋值了,结果就有可能新赋值的数据被删除了,为了解决类似的问题,python解释器简单粗暴的加了锁,即当一个线程运行时,其它人都不能动,这样就解决了上述的问题,  这可以说是Python早期版本的遗留问题。

RLock

import threading,time

def run1():
    print("grab the first part data")
    lock.acquire()
    global num
    num +=1
    lock.release()
    return num
def run2():
    print("grab the second part data")
    lock.acquire()
    global  num2
    num2+=1
    lock.release()
    return num2
def run3():
    lock.acquire()
    res = run1()
    print(‘--------between run1 and run2-----‘)
    res2 = run2()
    lock.release()
    print(res,res2)

if __name__ == ‘__main__‘:

    num,num2 = 0,0
    lock = threading.RLock()
    for i in range(10):
        t = threading.Thread(target=run3)
        t.start()

while threading.active_count() != 1:
    print(threading.active_count())
else:
    print(‘----all threads done---‘)
    print(num,num2)

Semaphore(信号量)

互斥锁 同时只允许一个线程更改数据,而Semaphore是同时允许一定数量的线程更改数据 ,比如厕所有3个坑,那最多只允许3个人上厕所,后面的人只能等里面有人出来了才能再进去。

import threading, time

def run(n):
    semaphore.acquire()
    time.sleep(1)
    print("run the thread: %s\n" % n)
    semaphore.release()

if __name__ == ‘__main__‘:
    num = 0
    semaphore = threading.BoundedSemaphore(5)  # 最多允许5个线程同时运行
    for i in range(20):
        t = threading.Thread(target=run, args=(i,))
        t.start()

while threading.active_count() != 1:
    pass  # print threading.active_count()
else:
    print(‘----all threads done---‘)
    print(num)

Timer

import threading
def hello():
    print("hello, world")

t = threading.Timer(3.0, hello)
t.start()

events实现线程间通信

通过Event来实现两个或多个线程间的交互,下面是一个红绿灯的例子,即起动一个线程做交通指挥灯,生成几个线程做车辆,车辆行驶按红灯停,绿灯行的规则。

使用

event = threading.Event()

event.set()

event.clear()

event.wait()

如果event被clear,wait会阻塞,一直等到event被set

import threading
import time

def light():
    count = 0

    while True:
        if count < 30:
            if not event.is_set():
                event.set()
            print("\033[32;1mgreen light-----\033[0m")
        elif count < 34:
            print("\033[33;1myellow light-----\033[0m")
        elif count < 60:
            if event.is_set():
                event.clear()
            print("\033[31;1mred light-----\033[0m")
        else:
            count = 0
        count+=1
        time.sleep(0.2)
def car(n):
    count = 0
    while True:
        event.wait()
        print("car [%s] is running...." % n )
        count +=1
        time.sleep(1)
event = threading.Event()

red_light = threading.Thread(target=light)red_light.start()

c1 = threading.Thread(target=car,args=(1,))c1.start()

队列

python2 Queue

python3 queue

import queue
#q = queue.Queue(maxsize=3)#先进先出,最大3
#q = queue.LifoQueue()#先进后出
q = queue.PriorityQueue()#优先级
q.put([1,1])
q.put([4,2])
q.put([3,3])#前面是优先级
# print(q.empty())#判断是否空
# print(q.full())#是否满q.qsize()队列大小
print(q.get())
print(q.get())
print(q.get())

生产者消费者模型

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题。该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度。

为什么要使用生产者和消费者模式

在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程。在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据。同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者。为了解决这个问题于是引入了生产者和消费者模式。

什么是生产者消费者模式

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。

import queue
import threading
import time

def consumer(name):
    while True:
        print(‘%s 取得骨头[%s]并吃了它‘%(name,q.get()))

def producer(name):
    count = 0
    while q.qsize()<5:
        print(‘%s生成了骨头‘%name,count)
        q.put(count)
        count += 1
        time.sleep(3)

q = queue.Queue(maxsize=4)

p = threading.Thread(target=producer,args=(‘alex‘,))
p2 = threading.Thread(target=producer,args=(‘alex1‘,))
c=threading.Thread(target=consumer,args=(‘ds‘,))
p.start()
p2.start()
c.start()

回执

import queue
import threading
import time

def consumer(name):
    while True:
        print(‘%s 取得骨头[%s]并吃了它‘%(name,q.get()))
        time.sleep(0.5)
        q.task_done()

def producer(name):
    count = 0
    for i in range(10):
        print(‘%s生成了骨头‘%name,count)
        q.put(count)
        count += 1
        time.sleep(1)
    q.join()
    print(‘-----all eat------‘)

q = queue.Queue(maxsize=4)

p = threading.Thread(target=producer,args=(‘alex‘,))
p2 = threading.Thread(target=producer,args=(‘alex1‘,))
c=threading.Thread(target=consumer,args=(‘ds‘,))
p.start()
p2.start()
c.start()

多进程

multiprocessing

multiprocessing is a package that supports spawning processes using an API similar to the threading module. The multiprocessing package offers both local and remote concurrency, effectively side-stepping the Global Interpreter Lock by using subprocesses instead of threads. Due to this, the multiprocessing module allows the programmer to fully leverage multiple processors on a given machine. It runs on both Unix and Windows.

subprocess支持使用多核

from multiprocessing import Process
import time

def f(name):
    time.sleep(1)
    print(‘hello‘,name)

if __name__ == ‘__main__‘:
    for i in range(5):
        p = Process(target=f,args=(‘alex‘,))
        p.start()

使用多进程开销远比多线程多

进程间通信

不同进程间内存是不共享的,要想实现两个进程间的数据交换,可以用以下方法:

Queue

from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, ‘hello‘])

if __name__ == ‘__main__‘:
    q = Queue()
    p = Process(target=f, args=(q,))#这里得把q传给f,进程复制一份数据
    p.start()
    print(q.get())  # prints "[42, None, ‘hello‘]"
    #p.join()

Pipe

from multiprocessing import Process, Pipe

def f(conn):
    conn.send([42, None, ‘hello‘])
    conn.close()

if __name__ == ‘__main__‘:
    parent_conn, child_conn = Pipe()
    p = Process(target=f, args=(child_conn,))
    p.start()
    print(parent_conn.recv())   # prints "[42, None, ‘hello‘]"
    p.join()

Manager实现进程间数据共享

两个进程修改一份数据

from multiprocessing import Process, Manager

def f(d, l):
    d[1] = ‘1‘
    d[‘2‘] = 2
    d[0.25] = None
    l.append(1)
    print(l)

if __name__ == ‘__main__‘:
    with Manager() as manager:
        d = manager.dict()

        l = manager.list(range(5))
        p_list = []
        for i in range(10):
            p = Process(target=f, args=(d, l))
            p.start()
            p_list.append(p)
        for res in p_list:
            res.join()

        print(d)
        print(l)

一般进程之间不进行数据的共享,开销大

进程同步

python2不加锁共享屏幕串行

python3

进程池

时间: 2024-11-09 04:45:01

Day10-线程进程的相关文章

线程 进程 多线程 多进程

进程和线程的主要区别在于多进程每个进程拥有独立存储空间,而多线程共享存储空间.对于单核CPU来讲,如果是阻塞操作,或者不耗时非阻塞操作,多进程/线程不会提高效率,这时候多进程/线程最有用的通常是耗时而又非阻塞的I/O操作. 打个比喻,一个人要看两部电影,可以看完一部再看另一部,也可以同时看,看一眼这个暂停,看一眼那个再暂停看回前一个,快速不停切换,你会觉得因为两部一起看所以先看完吗?理论上两部电影播放时间加起来是一样,所以看完所用时间应该一样.但是实际使用时间反而可能第一种方法快,为什么?切换是

线程进程概述

进程和线程目的,提高执行效率 1,单进程单线程,主进程,主线程 2,自定义线程: 主线程 主线程 子线程 进程: 优点,同时利用多个CPU,能同时进行多个操作 缺点,耗费资源,(重新开辟内存) 线程: 优点,共享内存,IO操作时候,创造并发操作 缺点,抢占资源 进程不是 越多越好,CPU个数=等于进程个数 线程也不是越多约好,具体案例具体分析 计算机中执行任务的最小单元是:线程 IO 操作利用CPU GIL,全局解释器锁 IO密集型(不用CPU) 多线程 计算密集型(用CPU) 多进程

我的读书笔记(线程进程)

线程有时候可以被称为微进程或轻量级进程,它的概念和进程十分相似,是一个可以被调度的单元,并且维护自己的堆栈和上下文环境,线程是附属进程的,一个进程可以包含1个或者多个线程,并且同一进程内的多个线程共享一块内存快和资源,一个线程是一个操作系统可调度的基本单元,但同时它的调度受限于包含该线程的进程,也就是说操作系统首先决定了下一个执行的进程,进而才会调度该进程内的线程 线程和进程最大的区别在于隔离性的问题,每个进程都被单独地隔离,拥有自己的内存快,独占的资源及运行数据,一个进程的崩溃不会影响到其他进

线程 进程学习

1,进程与线程 进程优点:同时利用多个cpu 工作,能同时进行多个操作 效率高 进程缺点:浪费内存 线程优点:共享内存,io操作的时候可以并发 线程缺点:抢占资源 进程不是越多越好  最好= cpu 线程也不是越多越好 具体案例 具体分析 请求上下文切换好时 计算机中执行任务最小单位是线程 IO密集型(不用cpu): 多线程 计算密集型(用cpu): 多进程 创建线程: import threading def f1(a): pass t = threading.Thread(target=f1

操作系统-并发-线程-进程

操作系统/应用程序 什么是操作系统? 精简的说法:操作系统就是一个人协调,管理和控制计算机硬件资源和软件资源的控制程序 操作系统位于计算机硬件与应用软件之间,本质也是一个软件.操作系统由操作系统的内核(运行于内核态,管理硬件资源)以及系统 调用(运行于用户态,为应用程序员写的应用程序提供系统调用接口)两部分组成,所以,单纯的说操作系统是运行于内核态的,是不准确的. 日常我们所知道的操作系统/应用程序: 硬件: -硬盘 -CPU -主板 -显卡 -内存 -电源 -...... 软件(装系统): -

15.python并发编程(线程--进程--协程)

一.进程:1.定义:进程最小的资源单位,本质就是一个程序在一个数据集上的一次动态执行(运行)的过程2.组成:进程一般由程序,数据集,进程控制三部分组成:(1)程序:用来描述进程要完成哪些功能以及如何完成(2)数据集:是程序在执行过程中所需要使用的一切资源(3)进程控制块:用来记录进程外部特征,描述进程的执行变化过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志.3.进程的作用:是想完成多任务并发,进程之间的内存地址是相互独立的二.线程:1.定义:最小的执行单位,线程的出现是为了

java 线程 进程

Java多线程(一).多线程的基本概念和使用 2012-09-10 16:06 5108人阅读 评论(0) 收藏 举报  分类: javaSE综合知识点(14)  版权声明:本文为博主原创文章,未经博主允许不得转载. 一.进程和线程的基础知识 1.进程和线程的概念 进程:运行中的应用程序称为进程,拥有系统资源(cpu.内存) 线程:进程中的一段代码,一个进程中可以有多段代码.本身不拥有资源(共享所在进程的资源) 在Java中,程序入口被自动创建为主线程,在主线程中可以创建多个子线程. 区别: 1

11 线程进程协程

1 线程 1.1 基本应用 1.1.1 标准线程(常用) import threading def f1(arg): print(arg) t = threading.Thread(target=f1, args=(123,)) t.start() 1.1.2 自定义线程 自定义线程类既threading.Thread流程,自定义run方法 import threading class MyThread(threading.Thread): #自定义类,继承threading.Thread类 d

第九天 线程 进程 协程 队列

详细链接http://www.cnblogs.com/alex3714/articles/5230609.html 1.线程:包含在进程中,是操作系统运算调度的最小单位,是一串指令的集合,直接与cpu交互 2进程:进程是一个程序各种资源的集合.操作系统通过管理这个集合进而运行程序,进程本身并不执行,进程通过调用线程来调度cpu. 3.不同点: 一个线程可以控制和操作同一进程里的其他线程,但是进程只能操作子进程 创建新线程很简单,但是创建一个子进程需要对父进程进行拷贝 线程共享内存,进程的内存是独

[进程与线程]进程、线程的生活

进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握. 最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂. 材料的地址:http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html 1. 计算机的核心是CPU,它承担了所有的计算任务.它就像一座工厂,时刻在运行. 2.  假定工厂的电力有限,一次只能供给一个车间使用.也就是说,一个车间开工