多线程多进程学习threading,锁,线程间数据状态读取。

http://www.cnblogs.com/alex3714/articles/5230609.html

python的多线程是通过上下文切换实现的,只能利用一核CPU,不适合CPU密集操作型任务,适合io操作密集型任务(如web高并发get读取网页文件)

io操作不占用CPU

计算操作占用CPU如 计算1+1

什么是线程(thread)?

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

A thread is an execution执行 context上下文, which is all the information a CPU needs to execute a stream流 of instructions指令.

一个线程就是一个执行的上下文,CPU执行指令所需的指令流。

Suppose假设 you're reading a book, and you want to take休息一下 a break right now,

假设你在读一本书,这个时候你想休息一下

 

but you want to be able to come back and resume reading from the exact point where you stopped.

但是你想回来的时候从上次精确的位置重新开始读

One way to achieve that is by jotting 笔记down the page number, line number, and word number.

一种实现的方法是去记下这个页码,行号,和字符位置。

 

So your execution context for reading a book is these 3 numbers.

所以你执行上下文切换需要记住这三个数字

If you have a roommate, and she's using the same technique 技巧, she can take 拿走the book while you're not using it, and resume reading from where she stopped.

如果您有一个室友,他也想用同样技巧,当你不用的时候,他把这个书拿走,从他上次读到的地方开始读。

Then you can take it back, and resume it from where you were.

你可以再拿回来,从你读到的位置重新开始读。

Threads work in the same way. 线程以同样的方式工作。

A CPU is giving you the illusion that it's doing multiple computations at the same time.

一核CPU给你的错觉(illusion) 是同时在处理多个计算

 

It does that by spending a bit of time on each computation.It can do that because it has an execution context for each computation.

他通过在每个计算上花费一丁点时间,因为他可以执行切换上下文在每个计算任务之间

Just like you can share a book with your friend, many tasks can share a CPU.

就像你可以共享一本书给你朋友一样,许多个任务可以共享一个CPU。

On a more technical level, an execution context (therefore a thread) consists of the values of the CPU's registers.

从技术层面讲,一个执行上下文就是一个线程,一个CPU寄存器的值的组合

Last: threads are different from processes.最后,线程和进程是不一样的。

A thread is a context of execution, while a process is a bunch of resources associated with a computation.

线程是一个上下文执行的指令,进程就是一簇(bunch)资源的集合,在计算时。

A process can have one or many threads.

一个进程可以有一个或多个线程

Clarification: the resources associated with a process include memory pages (all the threads in a process have the same view of the memory), file descriptors (e.g., open sockets), and security credentials (e.g., the ID of the user who started the process).

澄清一下,资源包括内存页(内存地址)(一个进程中的所有线程时共享内存的),如文件描述符(如套接字),安全证书,进程中的用户ID

什么是进程(process)?

An executing instance of a program is called a process.

每个程序执行的实例称作一个进程

Each process provides the resources needed to execute a program.

每个进程提供一个程序执行所需的资源

A process has a virtual address space, executable code, open handles to system objects, a security context, a unique process identifier,

一个进程有一个虚拟的内存地址,可执行代码,系统接口,安全的上下文,进程号

environment variables, a priority class, minimum and maximum working set sizes, and at least one thread of execution. Each process is started

环境变量,优先级类,最小和最大的工作空间限制,和最少一个线程执行

with a single thread, often called the primary thread, but can create additional threads from any of its threads.

每个进程启动的时候,会自动启动一个线程,第一个线程就是主线程,但是创建一个额外的线程。

 

进程与线程的区别?

【进程和线程没有可比性,进程只是资源的集合。】

启动一个线程要快于进程。启动一个进程相当于要建一个房间,启动一个线程相当于拉一个人进屋。

  1. Threads share the address space of the process that created it; processes have their own address space.线程个共享内存空间,进程是独立的
  2. Threads have direct access to the data segment of its process; processes have their own copy of the data segment of the parent process.线程共享数据的时候是一份数据,进程之间共享数据是进行了拷贝,比如两个子房间,共享数据是完全复制了一份。
  3. Threads can directly communicate with other threads of its process; processes must use interprocess communication to communicate with sibling processes.线程可以直接与进程的其他线程通信;进程必须使用进程间通信与同级进程通信
  4. New threads are easily created; new processes require duplication of the parent process.一个新的线程较容易创建,一个新进程需要拷贝一份数据
  5. Threads can exercise considerable control over threads of the same process; processes can only exercise control over child processes.线程可以对相同进程的线程进行相当大的控制;进程只能对子进程进行控制。
  6. Changes to the main thread (cancellation, priority change, etc.) may affect the behavior行为 of the other threads of the process; changes to the parent process does not affect child processes.对主线程的更改(取消、优先级更改等)可能会影响进程中其他线程的行为;对父进程的更改不会影响子进程。
#!/usr/bin/env python
# Author:Zhangmingda
import time,threading
'''常用多线程写法:for循环'''
def run(n):
    print('task:',n)
    time.sleep(2)

t_obj = []
'''每个线程启动后就直接启动下一个线程,不等上一个线程的执行结果,
为了获取每个线程执行的结果(等待线程执行结束),可以用.join(),'''
start_time = time.time()

for i in range(50):
    t = threading.Thread(target=run,args=(i,))
    t.start() #循环启动所有线程
    t_obj.append(t) #将每个线程对象保存下来
for i in t_obj: #对每个线程对象进行循环等待结束
    i.join()
print('cost_time(花费时间):',time.time() - start_time)
# t1 = threading.Thread(target=run,args=('t1',))
# t2 = threading.Thread(target=run,args=('t2',))
# t1.start()
# t2.start()
study_threading
#!/usr/bin/env python
# Author:Zhangmingda
import time,threading

 '''面向对象方式写法'''
 class Mythread(threading.Thread):
     def __init__(self,n):
         super(Mythread,self).__init__()
         self.n = n
     def run(self):
         print('running:',self.n)

 t1 = Mythread('t1')
 t2 = Mythread('t2')
 t1.start()
 t2.start()
多线程面向对象写法
C:\Users\Administrator\Desktop\Python3_study\venv\Scripts\python.exe C:/Users/Administrator/Desktop/Python3_study/day9/study_threading.py
task: 0
task: 1
task: 2
task: 3
task: 4
task: 5
task: 6
task: 7
task: 8
task: 9
task: 10
task: 11
task: 12
task: 13
task: 14
task: 15
task: 16
task: 17
task: 18
task: 19
task: 20
task: 21
task: 22
task: 23
task: 24
task: 25
task: 26
task: 27
task: 28
task: 29
task: 30
task: 31
task: 32
task: 33
task: 34
task: 35
task: 36
task: 37
task: 38
task: 39
task: 40
task: 41
task: 42
task: 43
task: 44
task: 45
task: 46
task: 47
task: 48
task: 49
cost_time(花费时间): 2.011706590652466
study_threading执行结果
#!/usr/bin/env python
# Author:Zhangmingda
'''面向对象方式写法'''
import threading,time

class Mythread(threading.Thread):
    def __init__(self,n):
        super(Mythread,self).__init__()
        self.n = n
    def run(self):
        print('running:',self.n)
        time.sleep(1)

t_obj = []
start_time = time.time()
for i in range(50):
    t = Mythread(i)
    t.start()
    t_obj.append(t)
for i in t_obj:
    i.join()
print('running OVER:time:',time.time() - start_time)
面向对象的for循环并发
C:\Users\Administrator\Desktop\Python3_study\venv\Scripts\python.exe C:/Users/Administrator/Desktop/Python3_study/day9/threading面向对象写法.py
running: 0
running: 1
running: 2
running: 3
running: 4
running: 5
running: 6
running: 7
running: 8
running: 9
running: 10
running: 11
running: 12
running: 13
running: 14
running: 15
running: 16
running: 17
running: 18
running: 19
running: 20
running: 21
running: 22
running: 23
running: 24
running: 25
running: 26
running: 27
running: 28
running: 29
running: 30
running: 31
running: 32
running: 33
running: 34
running: 35
running: 36
running: 37
running: 38
running: 39
running: 40
running: 41
running: 42
running: 43
running: 44
running: 45
running: 46
running: 47
running: 48
running: 49
running OVER:time: 1.008784294128418

Process finished with exit code 0
面向对象的for循环并发执行结果

 

#!/usr/bin/env python
# Author:Zhangmingda
import time,threading
'''常用多线程写法:for循环'''
def run(n):
    print('task:',n)
    time.sleep(2) #每个并行的子线程睡眠两秒
start_time = time.time()

for i in range(50):
    t = threading.Thread(target=run,args=(i,))
    t.setDaemon(True) #设置每个线程为主线程的守护进程(即当主线程结束时,子线程随之陪葬)
    t.start() #循环启动所有线程
time.sleep(1) #主线程睡眠1秒 (设置启动的子线程setDaemon为守护进程时,随主线程结束)
print('cost_time(花费时间):',time.time() - start_time)
'''此脚本的运行时间则为1秒多点自动结束'''
守护线程setDaemon(True)
C:\Users\Administrator\Desktop\Python3_study\venv\Scripts\python.exe C:/Users/Administrator/Desktop/Python3_study/day9/threading守护线程.py
task: 0
task: 1
task: 2
task: 3
task: 4
task: 5
task: 6
task: 7
task: 8
task: 9
task: 10
task: 11
task: 12
task: 13
task: 14
task: 15
task: 16
task: 17
task: 18
task: 19
task: 20
task: 21
task: 22
task: 23
task: 24
task: 25
task: 26
task: 27
task: 28
task: 29
task: 30
task: 31
task: 32
task: 33
task: 34
task: 35
task: 36
task: 37
task: 38
task: 39
task: 40
task: 41
task: 42
task: 43
task: 44
task: 45
task: 46
task: 47
task: 48
task: 49
cost_time(花费时间): 1.010725736618042

Process finished with exit code 0
守护线程随主线程结束结果

 并行的时候,仅仅有全局锁GLI是不行的,比如

#!/usr/bin/env python
# Author:Zhangmingda

import threading,time

num = 0
def run():
    global num
    num +=1

for i in range(1000):
    t = threading.Thread(target=run)
    t.start()
print('num:',num)
测试线程锁(Global Interpreter Lock) 

Ubuntu上python2运行的结果,

#!/usr/bin/env python
# Author:Zhangmingda
import threading,time

num = 0
lock = threading.Lock() #线程锁
t_obj = []
def run():
    lock.acquire() #每次调用这个函数就先加一把锁
    global num
    num +=1
    time.sleep(1)
    lock.release()#释放这个锁

for i in range(10):
    t = threading.Thread(target=run)
    t.start()
    t_obj.append(t)
for t in t_obj:
    t.join() #等待每个并行的线程结束
print('num:',num)

'''加锁使得整体并行效果编程了串行,总花费的时间为10秒'''
线程锁
C:\Users\Administrator\Desktop\Python3_study\venv\Scripts\python.exe C:/Users/Administrator/Desktop/Python3_study/day9/线程锁.py
num: 10

Process finished with exit code 0
线程锁运行结果

 线程锁:保证同一时刻只有一个线程在运行。

#!/usr/bin/env python
# Author:Zhangmingda
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)
递归锁
#!/usr/bin/env python
# Author:Zhangmingda
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.Lock() #嵌套锁出现锁死现象
    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)
嵌套的线程锁,不适用递归出现锁死现象示例代码

解释:在第二道锁里面,不使用递归锁出现的锁死出不来现象。线程总数始终保持在11个,如果使用递归锁就会结束

 

#!/usr/bin/env python
# Author:Zhangmingda
import threading,time
def run(n):
    semaphore.acquire()
    time.sleep(1)
    print('run the thread:%s'% n)
    semaphore.release()
    
if __name__ == "__main__":
    semaphore = threading.BoundedSemaphore(5) 
    #限制每一时刻只有5个线程运行,其它的请排队,然后运行中的5个每完成一个,就再进入运行队列一个线程
    for i in range(20):
        t = threading.Thread(target=run,args=(i,))
        t.start()
while threading.active_count() != 1:
    pass
else:
    print('--- all threads done---')
threading信号量
#!/usr/bin/env python
# Author:Zhangmingda

import threading,time

event = threading.Event()
def lighter():
    count = 0
    event.set() #设置事件标志位,表示开启绿灯
    while True:
        if  5 < count  < 10:
            event.clear() #清除标志位,表示红灯
            print('\033[41;1m红灯红灯,请停车\033[0m')
        elif count >= 10: #10秒循环一次
            count = 0 #重置变量
        else:
            event.set() #第一次循环后,重新设置标志位,开启绿灯
            print('\033[42;1m绿灯绿灯,走吧走吧\033[0m')
        count += 1
        time.sleep(1)

def car(name):
    while True:
        if event.is_set(): #判断绿灯标志位是否存在,存在就开车
            print('\033[32;1m %s 检测到绿灯,开车中....\033[0m'%name)
            time.sleep(1)
        else:
            print('\033[31;1m %s 等红灯...\033[0m'%name)
            event.wait() #等待标志位,不往下走

light = threading.Thread(target=lighter,)
light.start()

car1 = threading.Thread(target=car,args=('TesiLa',))
car1.start()
红绿灯+车(线程间检测状态)
 TesiLa 检测到绿灯,开车中....
绿灯绿灯,走吧走吧
绿灯绿灯,走吧走吧
 TesiLa 检测到绿灯,开车中....
 TesiLa 检测到绿灯,开车中....
绿灯绿灯,走吧走吧
红灯红灯,请停车
 TesiLa 等红灯...
红灯红灯,请停车
红灯红灯,请停车
红灯红灯,请停车
 TesiLa 检测到绿灯,开车中....
绿灯绿灯,走吧走吧
绿灯绿灯,走吧走吧
 TesiLa 检测到绿灯,开车中....

Process finished with exit code -1
车等灯开车运行效果

 ======================多进程=============================================

 

转载于:https://www.cnblogs.com/zhangmingda/p/9240134.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值