进程、线程、ThreadLlocal

1、线程是最小的执行单位,而进程中至少一个线程组;如果调度进程和线程,完全由操作系统决定,程序自己不能决定什么时候执行,执行多长时间

Unix/Linux操作系统提供了一个fork()系统调用,它非常特殊。普通的函数调用,调用一次,返回一次,但是fork()调用一次,返回两次,因为操作系统自动把当前进程(称为父进程)复制了一份(称为子进程),然后,分别在父进程和子进程内返回。

2、多进程:

在windows平台下,由于Python是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块

multiprocessing模块提供了一个Process类来代表一个进程对象,下面延时启动一个子进程并等待其结束:

3、python中os模块封装了常见的系统调用,其中就包括fork,可以在Python程序中轻松创建子进程

# !/user/bin/env python# -*- coding: utf-8 -*-from multiprocessing import Processimport os# 子进程要执行的代码def run_proc(name):    print ‘run child process %s (%s)...‘ % (name , os.getpid())

if __name__ == ‘__main__‘:    print ‘Parent process %s.‘ % os.getpid()    p = Process(target=run_proc,args=(‘test‘,)) # 创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动;比创建进程fork()还要简单    print ‘Process will start‘    p.start()    p.join()    # join()方法可以等待子进程结束后再继续往下运行,通常用于进程间的同步    print ‘Precess end‘

4、Pool :如果要启用大量的子进程,可以用进程池的方式批量创建子进程

from multiprocessing import Poolimport os,time,random

def long_time_task(name):    print ‘Run task %s (%s)...‘ % (name,os.getpid())    start = time.time()   # 返回当前时间的时间戳    time.sleep(random.random()*3)    end = time.time()      # 返回当前时间的时间戳    print ‘Task %s runs %0.2f seconds.‘ % (name,(end - start))

if __name__ == ‘__main__‘:    print ‘Parent process %s.‘ % os.getpid()    p = Pool()    for i in range(5):        p.apply_async(long_time_task,args=(i,))    print ‘Waiting for all subprocess done...‘    p.close()    p.join()    print ‘All subprocess done‘

5、进程间的通信

Process之间肯定是需要通信的,操作系统提供了很多机制来实现进程间的通信。python的multiprocessing模块包装了底层的机制,提供了Queue、Pipes等多种方式来交换数据

已Queue为例,在父进程中创建两个子进程,一个往Queue里写数据,一个从Queue里读数据:

from multiprocessing import Process,Queueimport os,time,randomdef write(q):   # 写数据进程执行代码    for value in [‘A‘,‘B‘,‘C‘]:        print ‘put %s to queue...‘ % value        q.put(value)        time.sleep(random.random())    # random.random()生成0和1之间的随机符点数def read(q):    # 读数据进程执行代码    while True:        value = q.get(True)        print ‘Get %s from queue.‘ % valueif __name__ == ‘__main__‘:    q = Queue()     # 父进程创建Queue,并传给各个子进程    pw = Process(target=write,args=(q,))    pr = Process(target=read, args=(q,))    pw.start()    # 启动子进程pw,写入    pr.start()     # 启动子进程pr,读取    pw.join()      # 等待pw结束    pr.terminate()  # pr进程里是死循环,无法等待其结束,只能强行终止

进程总结:

在Unix/Linux下,可以使用fork()调用实现多进程。

要实现跨平台的多进程,可以使用multiprocessing模块。

进程间通信是通过QueuePipes等实现的。

===============================================================================================

1、线程 : 由于线程是操作系统直接支持的执行单元,因此高级语言都内置多线程的支持,python也不例外,并且python的线程是真正的Posix Thread,而不是模拟出来的线程

Python的标准库中提供了两个模块:thread 和 threading ,thread是低级模块,threading是高级模块对thread进行了封装,绝大多数情况下,我们只需要使用threading这个高级模块

2、启动一个线程就是把一个函数传入并创建Thread实例,然后调用start()开始执行:

# !/user/bin/env python# -*- coding: utf-8 -*-# 线程import time,threadingdef loop():    print ‘thread %s is runniing...‘ % threading.current_thread().name  # 打印当前线程的名称    n = 0    while n < 5:        n = n + 1        print ‘thread %s >>> %s‘ % (threading.current_thread().name,n)        time.sleep(1)    print ‘thread %s ended‘ % threading.current_thread().nameprint ‘thread %s is running...‘ % threading.current_thread().name   # 打印当前的主线程t = threading.Thread(target=loop,name=‘LoopThread‘)t.start()t.join()print ‘thread %s ended.‘ % threading.current_thread().name

  由于任何线程默认就会启动一个线程,我们把该线程称为主线程,主线程又可以启动新的线程,python的threading模块有个current_thread()函数,返回当前线程的实例。主线程实例的名字叫MainThread,

子线程的名字在创建时指定,我们用LoopThread命名子线程。名字仅在打印时用来显示用。如果不给子线程起名字,python自动给线程名为Thread-1,Thread-2.....

2、Lock

多线程和多进程最大的不同在于:多进程中,同一个变量各自有一份拷贝存在于每个进程中,互不影响;多进程中,所有变量都由所有线程共享,所以任何一个变量都可以被任何一个线程修改,因此线程之间共享数据最大危险在于多个线程

同时改一个变量,把内容改乱了。此时就用到了Lock

import time,threadingbalance = 0 # 假定是银行存款lock = threading.Lock()def change_it(n):   # 该函数实现 现存后取,结果应该为0    global balance    balance = balance + n    balance = balance - ndef run_thread(n):    for i in range(1000):        lock.acquire()  # 先获取锁,锁定方法acquire()        try:            change_it(n)    # 放心地改        finally:            lock.release()  # 改完后一定要释放锁t1 = threading.Thread(target=run_thread,args=(5,))t2 = threading.Thread(target=run_thread,args=(8,))t1.start()t2.start()t1.join()t2.join()print balance

运行结果:0  当不加锁时,打印结果可能为负值,银行卡不应有负值;是因为多线程共享一个数据造成;加锁后结果一定为0;存n取出n

分析:当多个线程同时执行lock.acquire()时,只有一个线程能成功获取锁,然后继续执行代码,其他线程就继续等待直到获得锁为止

获得锁的线程用完后一定要释放锁,否则哪些苦苦等待锁的线程将永远等待下去,称为死线程。所以用try...finally...来确保锁一定会被释放

锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模 式执行,效率就大大地下降了。其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既 不能执行,

也无法结束,只能靠操作系统强制终止。

------------------------------------------------------------------------

1、ThreadLocal:当工作于多线程中的对象使用ThreadLocal维护变量时,ThreadLocal为每个使用该变量的线程分配一个独立的变量副本。每个线程独立改变自己的副本,不影响其他线程对应的变量副本

不同于线程同步:解决一个变量同一时刻被多个线程共享的问题(共享一个变量)

ThreadLocal:使得一个变量在多个线程中各自拥有自己的副本(实现资源的隔离)

时间: 2024-10-13 11:16:10

进程、线程、ThreadLlocal的相关文章

Linux下进程线程,Nignx与php-fpm的进程线程方式

1.进程与线程区别 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源. "进程——资源分配的最小单位,线程——程序执行的最小单位" 进程有独立的地

android 进程/线程管理(四)续----消息机制的思考(自定义消息机制)

继续分析handler 和looper 先看看handler的 public void dispatchMessage(Message msg) { if (msg.callback != null) { handleCallback(msg); } else { if (mCallback != null) { if (mCallback.handleMessage(msg)) { return; } } handleMessage(msg); } } 所以消息的处理分层三种,就是 1.传入一

进程/线程介绍

一.进程 进程可以认为是程序执行时的一个实例.进程是系统进行资源分配的独立的实体,且每个进程拥有独立 的地址空间.一个进程无法直接访问另一个进程的变量和数据结构,如果希望让一个进程访问另一个进程 的资源,需要使用进程间通信,比如:管道,有名管道,信号,信号量,消息队列,套接字等. 一个进程可以拥有多个线程,每个线程使用其所属进程的栈空间.线程和进程的一个主要区别是,同一程序内 的多个线程会共享部分状态,多个线程可以读写同一块内存(一个进程无法直接访问另一进程的内存).同时 每个线程还拥有自己的寄

进程线程协程那些事儿

一.进程与线程 1.进程 我们电脑的应用程序,都是进程,假设我们用的电脑是单核的,cpu同时只能执行一个进程.当程序出于I/O阻塞的时候,CPU如果和程序一起等待,那就太浪费了,cpu会去执行其他的程序,此时就涉及到切换,切换前要保存上一个程序运行的状态,才能恢复,所以就需要有个东西来记录这个东西,就可以引出进程的概念了. 进程就是一个程序在一个数据集上的一次动态执行过程.进程由程序,数据集,进程控制块三部分组成.程序用来描述进程哪些功能以及如何完成:数据集是程序执行过程中所使用的资源:进程控制

9 异常处理 操作系统 进程线程 队列+生产消费者模型 进程同步 回调函数

异常处理 异常就是程序运行时发生错误的信号,在python中,错误触发的异常如下 异常的种类: AttributeError 试图访问一个对象没有的树形,比如foo.x,但是foo没有属性x IOError 输入/输出异常:基本上是无法打开文件 ImportError 无法引入模块或包:基本上是路径问题或名称错误 IndentationError 语法错误(的子类) :代码没有正确对齐 IndexError 下标索引超出序列边界,比如当x只有三个元素,却试图访问x[5] KeyError 试图访

操作系统:进程/线程同步的方式和机制,进程间通信

一.进程/线程间同步机制. 临界区.互斥区.事件.信号量四种方式临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后,其他试图访问公共资源的线程将被挂起,并一直等到进入临界区的线程离开,临界区在被释放后,其他线程才可以抢占.2.互斥量:采用互斥对象机

进程/线程

进程/线程控制: 创建                  退出                      等待 多进程               fork()         exit()           wait() 多线程      pthread_create    pthread_exit()        pthread_join() 线程的同步与互斥: 线程的互斥:  互斥锁 初始化互斥锁 int pthread_mutex_init(pthread_mutex_t *mute

java 进程/线程

进程 OS并发的一个任务 CPU分时间片交替执行 宏观并行 微观串行 线程:在一个进程中并发的一个顺序执行流程 线程的组成: 1.数据 堆空间共享 栈空间独立 2.CPU 3.代码 Thread 线程对象 继承Thread类型 覆盖run方法 直接创建Thread对象 实现Runnable接口 实现run方法 先创建Runnable对象,再创建Thread对象 多线程共同访问同一个对象(临界资源),如果破坏了不可分割的操作(原子操作),就会发生数据不一致的情况 synchronized 同步 s

python基础-------进程线程(二)

Python中的进程线程(二) 一.python中的"锁" 1.GIL锁(全局解释锁) 含义: Python中的线程是操作系统的原生线程,Python虚拟机使用一个全局解释器锁(Global Interpreter Lock)来互斥线程对Python虚拟机的使用.为了支持多线程机制,一个基本的要求就是需要实现不同线程对共享资源访问的互斥,所以引入了GIL.GIL:在一个线程拥有了解释器的访问权之后,其他的所有线程都必须等待它释放解释器的访问权,即使这些线程的下一条指令并不会互相影响.在

进程/线程同步的方式和机制,进程间通信

转自: http://www.cnblogs.com/memewry/archive/2012/08/22/2651696.html 一.进程/线程间同步机制. 临界区.互斥区.事件.信号量四种方式临界区(Critical Section).互斥量(Mutex).信号量(Semaphore).事件(Event)的区别1.临界区:通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问.在任意时刻只允许一个线程对共享资源进行访问,如果有多个线程试图访问公共资源,那么在有一个线程进入后