线程、进程和协程

Treading用于提供线程相关的操作,线程是应用程序中工作的最小单元

#!/usr/bin/env python
# coding:utf-8
import threading
import  time

def show(arg):
    time.sleep(1)
    print ‘thread‘+str(arg)

for i in range(10):
    t = threading.Thread(target=show,args=(i,))
    t.start()

print ‘main thread stop‘

‘‘‘
打印结果:
main thread stop
thread0
thread5thread4thread1thread2

thread3
thread7thread6thread8

thread9
‘‘‘

上述代码创建了10个进程,然后控制器就交给CPU,CPU根据指定的算法进行调度,分片执行指令。出现顺序错乱的现象正常,因为他们都在同时抢占屏幕。

更多方法:

    start       线程准备就绪,等待CPU调度

    setName     为线程设置名称

    getName     获取线程名称

    setDaemon   设置为后台线程或前台线程(默认)

                如果是后台线程,主线程执行过程中,后台线程也在进行,主线程执行完毕后,后台线程不论成功与否,均停止

                如果是前台线程,主线程执行过程中,前台线程也在进行,主线程执行完毕后,等待前台线程也执行完成后,程序停止

    join        逐个执行每个线程,执行完毕后继续往下执行,该方法使得多线程变得无意义

    run         线程被cpu调度后执行Thread类对象的run方法

线程锁

由于线程之间是进行随机调度,并且每个线程可能只执行n条执行之后,CPU接着执行其他的线程。所以可能出现资源的抢占就像上面抢占屏幕输出,因此出现线程锁

#!/usr/bin/env python
# coding:utf-8
import threading
import  time
num = 0 

lock = threading.RLock()

def fun():
    # 加锁
    lock.acquire()
    global  num
    time.sleep(1)
    print num    # 解锁
    lock.release()

for i in range(10):
    t = threading.Thread(target=fun,)
    t.start()

打印输出:1-10  按照顺序

event

python线程的事件用于主线程控制其他线程的执行,事件主要提供了三个方法,set、wait、clear

事件处理的机制:全局定义了一个Flag,如果Flag值为False,那么当程序执行event.wait方法时就会阻塞,如果Flag值为True那么event.wait方法时便不再阻塞

clear:将Flag设置为Flase

set:将Flag设置为True

#!/usr/bin/env python
# coding:utf-8
import threading

def do(event):
    print ‘start‘
    # wait方法
    event.wait()
    print ‘execute‘

event_onj = threading.Event()
for i in range(10):
    t = threading.Thread(target=do,args=(event_onj,))
    t.start()
# 设置flag=false
event_onj.clear()

inp = raw_input(‘input:‘)
if inp == ‘true‘:
    # 设置flag=true
    event_onj.set()

上述代码的执行:首先会全部10个进程都执行到print ‘start’,然后执行event_onj.clear(),将状态设置为false;处在在等待状态,当我输入true的时候,执行event_onj.set(),状态有设置为true。继续往下执行

下面是执行结果:

start
start
start
start
start
start
start
start
start
startinput:
true
executeexecute
executeexecuteexecute
executeexecute
 executeexecuteexecute

多线程的使用

创建一个线程

#!/usr/bin/env python
# coding:utf-8
from multiprocessing import  Process
import  threading
import  time
def do(i):
    print ‘say hi‘,i

for i in range(2):
    p = Process(target=do,args=(i,))
    p.start()

注意:因为进程之间的数据需要各自持有一份,所以创建进程需要非常大的开销(windows下不能创建Process)

进程数据共享

进程各自持有一份数据,默认无法共享数据

共享方式一:Array

#!/usr/bin/env python
# coding:utf-8
from multiprocessing import  Process,Array
# 创建一个只包含数字类型的一个数组(列表)
# 数组的个数是不可变的
temp = Array(‘i‘,[1,2,3,4,5,6])

def Foo(i):
    temp[i] = 100+i
    for item in temp:
        print i,‘=======‘,item

for i in range(2):
    p = Process(target=Foo,args=(i,))
    p.start()

共享方式二:manage.dict

#!/usr/bin/env python
# coding:utf-8
from multiprocessing import Process,Manager

manage = Manager()
dic = manage.dict()

def Foo(i):
    dic[i] = 100+i
    print dic.values()

for i in range(2):
    p = Process(target=Foo,args=(i,))
    p.start()
    p.join()

共享数据的类型

    ‘c‘: ctypes.c_char,  ‘u‘: ctypes.c_wchar,
    ‘b‘: ctypes.c_byte,  ‘B‘: ctypes.c_ubyte,
    ‘h‘: ctypes.c_short, ‘H‘: ctypes.c_ushort,
    ‘i‘: ctypes.c_int,   ‘I‘: ctypes.c_uint,
    ‘l‘: ctypes.c_long,  ‘L‘: ctypes.c_ulong,
    ‘f‘: ctypes.c_float, ‘d‘: ctypes.c_double

当创建进程时(非使用时),共享数据会被拿到子进程中,当进程中执行完毕后,再赋值给原值。

这里也是可以使用进程锁

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from multiprocessing import Process, Array, RLock

def Foo(lock,temp,i):
    """
    将第0个数加100
    """
    lock.acquire()
    temp[0] = 100+i
    for item in temp:
        print i,‘----->‘,item
    lock.release()

lock = RLock()
temp = Array(‘i‘, [11, 22, 33, 44])

for i in range(20):
    p = Process(target=Foo,args=(lock,temp,i,))
    p.start()

进程池

进程池内部维护一个进程序列,当使用时,则去进程池中获取一个进程,如果进程池序列中没有可供使用的进进程,那么程序就会等待,直到进程池中有可用进程为止。

进程池中有两个方法:

1:apply 去进程池中申请一个进程

2:apply_async  去进程池中申请一个进程

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from  multiprocessing import Process,Pool
import time

def Foo(i):
    time.sleep(2)
    return i+100

# 这里的arg就是执行Foo函数的返回值
def Bar(arg):
    print arg
# 创建五个进程
pool = Pool(5)
print pool.apply(Foo,(1,))
print pool.apply(Foo,(2,))
print pool.apply(Foo,(3,))
print pool.apply(Foo,(4,))
print pool.apply(Foo,(5,))
# 上面五个的其中一个执行完毕后,有空余的进程后,执行第六个进程。
print pool.apply(Foo,(6,))

for i in range(10):
    # 循环执行10个进程,每个进程执行完毕后,都执行callback方法中的Bar
    pool.apply_async(func=Foo, args=(i,),callback=Bar)

print ‘end‘
pool.close()
pool.join()#进程池中进程执行完毕后再关闭,如果注释,那么程序直接关闭。

协程

线程和进程的操作是由程序触发系统接口,最后的执行者是系统;协程的操作则是程序员。

协程存在的意义:对于多线程应用,CPU通过切片的方式来切换线程间的执行,线程切换时需要耗时(保存状态,下次继续)。协程,则只使用一个线程,在一个线程中规定某个代码块执行顺序。

协程的适用场景:当程序中存在大量不需要CPU的操作时(IO),适用于协程;

说白了就是由程序员来控制程序的执行

协程是对线程的分片

这里的greenlet需要安装

#!/usr/bin/env python
# -*- coding:utf-8 -*-

from greenlet import greenlet

def test1():
    print 12
    # 切换到协程2去执行
    gr2.switch()
    print 34
    gr2.switch()

def test2():
    print 56
    # 切换到协程1去执行
    gr1.switch()
    print 78

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

这个执行有点像yield

IO操作特别多的情况下用协程比较合适。计算多的情况不要用协程。

gevent

#!/usr/bin/env python
# -*- coding:utf-8 -*-
from gevent import monkey; monkey.patch_all()
import gevent
import urllib2

# import urllib
# 请求www.baidu.com
# t = urllib.urlopen(‘http://www.baidu.com‘)
# print t.read()

def f(url):
    print(‘GET: %s‘ % url)
    # 发一个http请求
    resp = urllib2.urlopen(url)
    data = resp.read()
    print(‘%d bytes received from %s.‘ % (len(data), url))

gevent.joinall([
        # 这里是三个协程,是没有阻塞的,执行F函数,谁返回,谁接着就执行
        gevent.spawn(f, ‘https://www.python.org/‘),
        gevent.spawn(f, ‘https://www.yahoo.com/‘),
        gevent.spawn(f, ‘https://github.com/‘),
])

 

时间: 2024-10-05 23:20:39

线程、进程和协程的相关文章

Python之路【第七篇】:线程、进程和协程

Python之路[第七篇]:线程.进程和协程 Python线程 Threading用于提供线程相关的操作,线程是应用程序中工作的最小单元. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 #!/usr/bin/env python # -*- coding:utf-8 -*- import threading import time   def show(arg):     time.sleep(1)     print 'thread'+str(arg)   for i in

Python菜鸟之路:Python基础-线程、进程、协程

上节内容,简单的介绍了线程和进程,并且介绍了Python中的GIL机制.本节详细介绍线程.进程以及协程的概念及实现. 线程 基本使用 方法1: 创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入 import threading import time def worker(): time.sleep(2) print("test") for i in range(5): t = threading.Thread(target=

Python:线程、进程与协程(1)——概念

最近的业余时间主要放在了学习Python线程.进程和协程里,第一次用python的多线程和多进程是在两个月前,当时只是简单的看了几篇博文然后就跟着用,没有仔细去研究,第一次用的感觉它们其实挺简单的,最近这段时间通过看书, 看Python 中文官方文档等等相关资料,发现并没有想想中的那么简单,很多知识点需要仔细去理解,Python线程.进程和协程应该是Python的高级用法.Python的高级用法有很多,看看Python 中文官方文档就知道了,当然有时间看看这些模块是怎么实现的对自己的提高是很有帮

Python:线程、进程与协程(4)——multiprocessing模块(1)

multiprocessing模块是Python提供的用于多进程开发的包,multiprocessing包提供本地和远程两种并发,通过使用子进程而非线程有效地回避了全局解释器锁. (一)创建进程Process 类 创建进程的类,其源码在multiprocessing包的process.py里,有兴趣的可以对照着源码边理解边学习.它的用法同threading.Thread差不多,从它的类定义上就可以看的出来,如下: class Process(object):     '''     Proces

Python:线程、进程与协程(3)——Queue模块及源码分析

Queue模块是提供队列操作的模块,队列是线程间最常用的交换数据的形式.该模块提供了三种队列: Queue.Queue(maxsize):先进先出,maxsize是队列的大小,其值为非正数时为无线循环队列 Queue.LifoQueue(maxsize):后进先出,相当于栈 Queue.PriorityQueue(maxsize):优先级队列. 其中LifoQueue,PriorityQueue是Queue的子类.三者拥有以下共同的方法: qsize():返回近似的队列大小.为什么要加"近似&q

Python:线程、进程与协程(2)——threading模块(1)

上一篇博文介绍了Python中线程.进程与协程的基本概念,通过这几天的学习总结,下面来讲讲Python的threading模块.首先来看看threading模块有哪些方法和类吧. 主要有: Thread :线程类,这是用的最多的一个类,可以指定线程函数执行或者继承自它都可以实现子线程功能. Timer:与Thread类似,但要等待一段时间后才开始运行,是Thread的子类. Lock :原锁,是一个同步原语,当它锁住时不归某个特定的线程所有,这个可以对全局变量互斥时使用. RLock :可重入锁

线程、进程、协程和GIL(一)

参考链接:https://www.cnblogs.com/alex3714/articles/5230609.html https://www.cnblogs.com/work115/p/5620272.html 编程离不开并发,而并发的基础就离不开线程.进程.协程.那么什么是线程.进程.协程呢? 进程: 进程是对资源进行分配和调度的最小单位,是操作系统结构的基础,是线程的容器(就像是一幢房子,一个空壳子,并不能运动). 线程的概念主要有两点: 1.进程是一个实体,每个进程都有自己的地址空间,一

进程池与线程池、协程、协程实现TCP服务端并发、IO模型

进程池与线程池.协程.协程实现TCP服务端并发.IO模型 一.进程池与线程池 1.线程池 ''' 开进程开线程都需要消耗资源,只不过两者比较的情况下线程消耗的资源比较少 在计算机能够承受范围内最大限度的利用计算机 什么是池? 在保证计算机硬件安全的情况下最大限度的利用计算机 池其实是降低了程序的运行效率,但是保证了计算机硬件的安全 (硬件的发展跟不上软件的速度) ''' from concurrent.futures import ThreadPoolExecutor import time p

异步回调,事件,线程池与协程

在发起一个异步任务时,指定一个函数任务完成后调用函数 为什么需要异步 在使用线程池或进程池提交任务时想要任务的结果然后将结果处理,调用shudown 或者result会阻塞 影响效率,这样的话采用异步调用 比如result本来是用水壶烧水烧开了拿走,烧下一个 用shutdown可以将水壶一起烧但是一个一个拿走 call_done_back是一起烧,每个好了会叫你拿走做其他事 . 1.使用进程池时,回调函数都是主进程中执行执行 2. 使用线程池时,回调函数的执行线程是不确定的,哪个线程空闲就交给哪

异步调用,线程队列,时间,协程

异步的使用场景 爬虫: 1.从目标站点下载网页数据,本质是HTML格式字符串 2.用re从字符串中提取出你所需要的数据 #使用进程池 from concurrent.futures import ProcessPoolExecutor import requests,re,os def get_data(url): print('%s正在请求%s'%(os.getpid(),url)) response = requests.get(url) #获取网页数据包含报头 print('%s请求%s成