python线程

进程与线程的历史

我们都知道计算机是由硬件和软件组成的。硬件中的CPU是计算机的核心,它承担计算机的所有任务。 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源的管理和分配、任务的调度。 程序是运行在系统上的具有某种功能的软件,比如说浏览器,音乐播放器等。 每次执行程序的时候,都会完成一定的功能,比如说浏览器帮我们打开网页,为了保证其独立性,就需要一个专门的管理和控制执行程序的数据结构——进程控制 块。 进程就是一个程序在一个数据集上的一次动态执行过程。 进程一般由程序、数据集、进程控制块三部分组成。我们编 写的程序用来描述进程要完成哪些功能以及如何完成;数据集则是程序在执行过程中所需要使用的资源;进程控制块用来记录进程的外部特征,描述进程的执行变化 过程,系统可以利用它来控制和管理进程,它是系统感知进程存在的唯一标志。

在早期的操作系统里,计算机只有一个核心,进程执行程序的最小单位,任务调度采用时间片轮转的抢占式方式进行进程调度。每个进程都有各自的一块独立的内 存,保证进程彼此间的内存地址空间的隔离。 随着计算机技术的发展,进程出现了很多弊端,一是进程的创建、撤销和切换的开销比较大,二是由于对称多处理机(对称多处理机 (SymmetricalMulti-Processing)又叫SMP,是指在一个计算机上汇集了一组处理器(多CPU),各CPU之间共享内存子系统 以及总线结构)的出现,可以满足多个运行单位,而多进程并行开销过大。 这个时候就引入了线程的概念。 线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合 和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能。 线程没有自己的系统资源,只拥有在运行时必不可少的资源。但线程可以与同属与同一进程的其他线程共享进程所拥有的其他资源。

进程与线程之间的关系

线程是属于进程的,线程运行在进程空间内,同一进程所产生的线程共享同一内存空间,当进程退出时该进程所产生的线程都会被强制退出并清除。线程可与属于同 一进程的其它线程共享进程所拥有的全部资源,但是其本身基本上不拥有系统资源,只拥有一点在运行中必不可少的信息(如程序计数器、一组寄存器和栈)。

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 importthreading4 importtime,datetime5

6 defshow(arg):7 time.sleep(5)8 print('thread'+str(arg),time.time())9

10

11 for i in range(4):12 t = threading.Thread(target=show, args=(i,))13 #t.setName('name%s' % i)

14 #print(t.name)

15 #t.setDaemon(False) #默认是False, 如果改成True,主线程不等待子线程

16

17 t.start()18 t.run() #立即执行

19 t.join(2)20 print('main thread stop')

上述代码创建了10个“前台”线程,然后控制器就交给了CPU,CPU根据指定算法进行调度,分片执行指令。

更多方法:

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

setName      为线程设置名称

getName      获取线程名称

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

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

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

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

run              线程被cpu调度后自动执行线程对象的run方法

线程锁threading.RLock和threading.Lock

我们使用线程对数据进行操作的时候,如果多个线程同时修改某个数据,可能会出现不可预料的结果,为了保证数据的准确性,引入了锁的概念

例:假设列表A的所有元素就为0,当一个线程从前向后打印列表的所有元素,另外一个线程则从后向前修改列表的元素为1,那么输出的时候,列表的元素就会一部分为0,一部分为1,这就导致了数据的不一致。锁的出现解决了这个问题。

1 #未加锁

2 importthreading3 importtime4

5 gl_num =06

7 defshow(arg):8 globalgl_num9 time.sleep(1)10 gl_num += 1

11 print(gl_num)12

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

17 print('main thread stop')

未加锁代码

1 线程锁2 importthreading3 importtime4

5 gl_num =06

7 lock = threading.RLock() #获取一个锁的对象

8

9 defFunc():10 lock.acquire() #创建一把锁

11 global gl_num #声明全局变量

12 gl_num +=1

13 time.sleep(1)14 print(gl_num)15 lock.release() #更改完释放锁

16

17 for i in range(10):18 t = threading.Thread(target=Func) #利用线程执行,执行10次 结果1,2,3,4,5,6.。

19 t.start()

线程锁

threading.Event

Event是线程间通信最间的机制之一:一个线程发送一个event信号,其他的线程则等待这个信号。用于主线程控制其他线程的执行。 Events 管理一个flag,这个flag可以使用set()设置成True或者使用clear()重置为False,wait()则用于阻塞,在flag为 True之前。flag默认为False。

Event.wait([timeout]) : 堵塞线程,直到Event对象内部标识位被设为True或超时(如果提供了参数timeout)。

Event.set() :将标识位设为Ture

Event.clear() : 将标识伴设为False。

Event.isSet() :判断标识位是否为Ture。

1 event2 importthreading3

4

5 def do(event): #定义一个函数,传递参数envent,其实就是传递了一个对象

6 print 'start'

7 event.wait() #True则不阻塞

8 print 'execute'

9

10

11 event_obj =threading.Event()12 for i in range(10):13 t = threading.Thread(target=do, args=(event_obj,)) #传递执行函数和参数

14 t.start()15

16 event_obj.clear() #将“Flag”设置为False

17 inp = raw_input('input:')18 if inp == 'true':19 event_obj.set() #set默认为True

event

queue模块

Queue 就是对队列,它是线程安全的

举例来说,我们去肯德基吃饭。厨房是给我们做饭的地方,前台负责把厨房做好的饭卖给顾客,顾客则去前台领取做好的饭。这里的前台就相当于我们的队列。

这个模型也叫生产者-消费者模型。

复制代码

import queue

q = queue.Queue(maxsize=0) # 构造一个先进显出队列,maxsize指定队列长度,为0 时,表示队列长度无限制。

q.join() # 等到队列为kong的时候,在执行别的操作

q.qsize() # 返回队列的大小 (不可靠)

q.empty() # 当队列为空的时候,返回True 否则返回False (不可靠)

q.full() # 当队列满的时候,返回True,否则返回False (不可靠)

q.put(item, block=True, timeout=None) # 将item放入Queue尾部,item必须存在,可以参数block默认为True,表示当队列满时,会等待队列给出可用位置,

为False时为非阻塞,此时如果队列已满,会引发queue.Full 异常。 可选参数timeout,表示 会阻塞设置的时间,过后,

如果队列无法给出放入item的位置,则引发 queue.Full 异常

q.get(block=True, timeout=None) # 移除并返回队列头部的一个值,可选参数block默认为True,表示获取值的时候,如果队列为空,则阻塞,为False时,不阻塞,

若此时队列为空,则引发 queue.Empty异常。 可选参数timeout,表示会阻塞设置的时候,过后,如果队列为空,则引发Empty异常。

q.put_nowait(item) # 等效于 put(item,block=False)

q.get_nowait() # 等效于 get(item,block=False)

生产者--消费者:

1 #!/usr/bin/env python

2 importQueue3 importthreading4

5

6 message = Queue.Queue(10)7

8

9 defproducer(i):10 whileTrue:11 message.put(i)12

13

14 defconsumer(i):15 whileTrue:16 msg =message.get()17

18

19 for i in range(12):20 t = threading.Thread(target=producer, args=(i,))21 t.start()22

23 for i in range(10):24 t = threading.Thread(target=consumer, args=(i,))25 t.start()

生产者消费者模型

线程池

1 importqueue2 importthreading3 importcontextlib4 importtime5

6 StopEvent =object()7

8

9 classThreadPool(object):10

11 def __init__(self, max_num):12 self.q =queue.Queue()13 self.max_num =max_num14

15 self.terminal =False16 self.generate_list =[]17 self.free_list =[]18

19 def run(self, func, args, callback=None):20 """

21 线程池执行一个任务22 :param func: 任务函数23 :param args: 任务函数所需参数24 :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)25 :return: 如果线程池已经终止,则返回True否则None26 """

27

28 if len(self.free_list) == 0 and len(self.generate_list) <29 self.generate_thread w="(func," args callback self.q.put>

33 defgenerate_thread(self):34 """

35 创建一个线程36 """

37 t = threading.Thread(target=self.call)38 t.start()39

40 @contextlib.contextmanager41 defworker_state(self, xxx, val):42 xxx.append(val)43 try:44 yield

45 finally:46 xxx.remove(val)47

48 defcall(self):49 """

50 循环去获取任务函数并执行任务函数51 """

52 current_thread =threading.currentThread53 self.generate_list.append(current_thread)54

55 event =self.q.get()56 while event !=StopEvent:57

58 func, arguments, callback =event59 try:60 result = func(*arguments)61 status =True62 exceptException as e:63 status =False64 result =e65

66 if callback is notNone:67 try:68 callback(status, result)69 exceptException as e:70 pass

71

72 if self.terminal: #False

73 event =StopEvent74 else:75 #self.free_list.append(current_thread)

76 #event = self.q.get()

77 #self.free_list.remove(current_thread)

78 with self.worker_state(self.free_list, current_thread):79 event =self.q.get()80 else:81 self.generate_list.remove(current_thread)82

83 defclose(self):84 num =len(self.generate_list)85 whilenum:86 self.q.put(StopEvent)87 num -= 1

88

89 #终止线程(清空队列)

90 defterminate(self):91

92 self.terminal =True93

94 whileself.generate_list:95 self.q.put(StopEvent)96 self.q.empty()97 importtime98

99 defwork(i):100 print(i,"----")101

102 pool = ThreadPool(10)103 for item in range(50):104 pool.run(func=work, args=(item,))105

106 pool.terminate()

完整版线程池

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 importqueue4 importthreading5 importcontextlib6 importtime7

8 StopEvent = object() #定义标记的意义在于任务结束后退出的标记

9

10

11 classThreadPool(object):12

13 def __init__(self, max_num):14 self.q = queue.Queue() #定义队列无限大

15 self.max_num = max_num #定义最大值

16

17 self.terminal = False #定义为false

18 self.generate_list = [] #多少个进程正在执行

19 self.free_list = [] #定义空闲列表--空闲线程 初始化各种属性

20

21 def run(self, func, args, callback=None):22 """

23 线程池执行一个任务24 :param func: 任务函数25 :param args: 任务函数所需参数26 :param callback: 任务执行失败或成功后执行的回调函数,回调函数有两个参数1、任务函数执行状态;2、任务函数返回值(默认为None,即:不执行回调函数)27 :return: 如果线程池已经终止,则返回True否则None28 """

29

30 if len(self.free_list) == 0 and len(self.generate_list) <31 self.generate_thread w="(func," args callback self.q.put>

35 defgenerate_thread(self):36 """

37 创建一个线程38 """

39 t = threading.Thread(target=self.call)#并执行call方法

40 t.start()41

42 defcall(self):43 """

44 循环去获取任务函数并执行任务函数45 """

46 current_thread = threading.currentThread #拿到当前线程

47 self.generate_list.append(current_thread) #添加到正在使用线程队列

48

49 event = self.q.get() #--这里是一个获取到的元组w=()....

50 while event !=StopEvent:51

52 func, arguments, callback = event #w= (func, args, callback)

53 try:54 result = func(*arguments) #执行任务 ret = aaa() --def aaa(): return 1

55 status =True56 except Exception as e: #如果我这个任务报错

57 status =False58 result =e59

60 if callback is not None: #这是一个返回值

61 try:62 callback(status, result)63 exceptException as e:64 pass

65

66 self.free_list.append(current_thread) #---记得看上下文代码,执行完任务,把这个线程放到空闲队列里面

67 event = self.q.get()#当前的状态应该是没任务,线程等待任务,不结束

68 self.free_list.remove(current_thread) #获取任务移除休息线程

69 else:70 if event =StopEvent:71 self.generate_list.remove(current_thread) #移除当前正在运行的线程,等他运行完

72

73 defclose(self):74 num =len(self.generate_list)75 whilenum:76 self.q.put(StopEvent)#77 num -= 1

78

79

80 importtime81

82 defwork(i):83 print(i)84

85 pool = ThreadPool(10) #定义最大线程为10个,实例化,并初始化

86 for item in range(50): #创建了50个任务

87 pool.run(func=work, args=(item,)) #执行work函数,args是传参

88

89 pool.close() #关闭线程池

理解注释版线程池

Python 进程

1 from multiprocessing importProcess2 importthreading3 importtime4

5 deffoo(i):6 print 'say hi',i7

8 for i in range(10):9 p = Process(target=foo,args=(i,))10 p.start()

注意:由于进程之间的数据需要各自持有一份,所以创建进程需要的非常大的开销。

multiprocessing模块

multiprocessing是python的多进程管理包,和threading.Thread类似。直接从侧面用subprocesses替换线程使用GIL的方式,由于这一点,multiprocessing模块可以让程序员在给定的机器上充分的利用CPU。

在multiprocessing中,通过创建Process对象生成进程,然后调用它的start()方法,

各种参数的意思:

注意:

start() 开始进程

setDaemon(True):守护进程:mutilprocess.setDaemon(True)

terminate():退出进程:最好使用 poison pill,强制的使用terminate()

is_alive(): 进程创建之后,可以使用multiprocessing对象的is_alive方法查看线程是否运行,为True则运行

join():阻塞当前进程,直到调用join方法的那个进程执行完,再继续执行当前进程。|  或者也可以理解为: 进程池中进程执行完毕后在关闭, 如果注释, 那么程序直接关闭

守护进程

守护进程就是不阻挡主程序退出,自己干自己的 mutilprocess.setDaemon(True)

就这句

等待守护进程退出,要加上join,join可以传入浮点数值,等待n久就不等了

importmultiprocessingimporttimeimportsysdefdaemon():

name=multiprocessing.current_process().nameprint 'Starting:', name

time.sleep(2)print 'Exiting :', namedefnon_daemon():

name=multiprocessing.current_process().nameprint 'Starting:', nameprint 'Exiting :', nameif __name__ == '__main__':

d= multiprocessing.Process(name='daemon',

target=daemon)

d.daemon=True

n= multiprocessing.Process(name='non-daemon',

target=non_daemon)

n.daemon=False

d.start()

n.start()

d.join(1)print 'd.is_alive()', d.is_alive()

n.join()

View Code

终止进程

最好使用 poison pill,强制的使用terminate()

注意 terminate之后要join,使其可以更新状态

importmultiprocessingimporttimedefslow_worker():print 'Starting worker'time.sleep(0.1)print 'Finished worker'

if __name__ == '__main__':

p= multiprocessing.Process(target=slow_worker)print 'BEFORE:', p, p.is_alive()

p.start()print 'DURING:', p, p.is_alive()

p.terminate()print 'TERMINATED:', p, p.is_alive()

p.join()print 'JOINED:', p, p.is_alive()

简单示例:

1 from multiprocessing importProcess2

3 deff(name):4 print('hello', name)5

6 if __name__ == '__main__':7 p = Process(target=f, args=('bob',))8 p.start()9 p.join()

join()方法的示例:

from multiprocessing importProcessimportos, time, randomdefr1(process_name):for i in range(5):print process_name, os.getpid() #打印出当前进程的id

time.sleep(random.random())defr2(process_name):for i in range(5):print process_name, os.getpid() #打印出当前进程的id

time.sleep(random.random())if __name__ == "__main__":print "main process run..."p1= Process(target=r1, args=('process_name1', ))

p2= Process(target=r2, args=('process_name2', ))

p1.start()

p2.start()#p1.join()

#p2.join()

print "main process runned all lines..."

进程数据共享

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

1 #!/usr/bin/env python

2 #coding:utf-8

3

4 from multiprocessing importProcess5 from multiprocessing importManager6

7 importtime8

9 li =[]10

11 deffoo(i):12 li.append(i)13 print 'say hi',li14

15 for i in range(10):16 p = Process(target=foo,args=(i,))17 p.start()18

19 print 'ending',li

进程间无数据共享

1 #方法一,Array

2 from multiprocessing importProcess,Array3 temp = Array('i', [11,22,33,44])4

5 defFoo(i):6 temp[i] = 100+i7 for item intemp:8 print i,'----->',item9

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

14 #方法二:manage.dict()共享数据

15 from multiprocessing importProcess,Manager16

17 manage =Manager()18 dic =manage.dict()19

20 defFoo(i):21 dic[i] = 100+i22 printdic.values()23

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

1 'c': ctypes.c_char, 'u': ctypes.c_wchar,2 'b': ctypes.c_byte, 'B': ctypes.c_ubyte,3 'h': ctypes.c_short, 'H': ctypes.c_ushort,4 'i': ctypes.c_int, 'I': ctypes.c_uint,5 'l': ctypes.c_long, 'L': ctypes.c_ulong,6 'f': ctypes.c_float, 'd': ctypes.c_double

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

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3

4 from multiprocessing importProcess, Array, RLock5

6 defFoo(lock,temp,i):7 """

8 将第0个数加1009 """

10 lock.acquire()11 temp[0] = 100+i12 for item intemp:13 print i,'----->',item14 lock.release()15

16 lock =RLock()17 temp = Array('i', [11, 22, 33, 44])18

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

进程锁实例

进程池

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

进程池中有两个方法:

apply

apply_async

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3 from multiprocessing importProcess,Pool4 importtime5

6 defFoo(i):7 time.sleep(2)8 return i+100

9

10 defBar(arg):11 printarg12

13 pool = Pool(5) #进程池14 #print pool.apply(Foo,(1,))

15 #print pool.apply_async(func =Foo, args=(1,)).get()

16

17 for i in range(10):18 pool.apply_async(func=Foo, args=(i,),callback=Bar)#但它是非阻塞且支持结果返回进行回调 (回调 ret = pool.apply....)19

20 print 'end'

21 pool.close()#关闭进程池,不再接受新的进程

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

1 #apply和apply_async

2

3

4 from multiprocessing importPool5 importtime6

7 deff1(a):8 time.sleep(1)9 print(a)10 return 1000

11 deff2(arg):12 print(arg)13

14 if __name__ == '__main__':15 pool = Pool(5)16 for i in range(10):17 pool.apply_async(func=f1, args=(i,), callback=f2)18 #pool.apply(func=f1, args=(i,))

19 print('1111111')20

21 pool.close()22 pool.join()

window环境代码

协程

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

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

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

greenlet

1 #!/usr/bin/env python

2 #-*- coding:utf-8 -*-

3

4

5 from greenlet importgreenlet6

7

8 deftest1():9 print 12

10 gr2.switch()11 print 34

12 gr2.switch()13

14

15 deftest2():16 print 56

17 gr1.switch()18 print 78

19

20 gr1 =greenlet(test1)21 gr2 =greenlet(test2)22 gr1.switch()

gevent

1 importgevent2

3 deffoo():4 print('Running in foo')5 gevent.sleep(0)6 print('Explicit context switch to foo again')7

8 defbar():9 print('Explicit context to bar')10 gevent.sleep(0)11 print('Implicit context switch back to bar')12

13 gevent.joinall([14 gevent.spawn(foo),15 gevent.spawn(bar),16 ])

遇到IO操作自动切换:

1 from gevent importmonkey; monkey.patch_all()2 importgevent3 importurllib24

5 deff(url):6 print('GET: %s' %url)7 resp =urllib2.urlopen(url)8 data =resp.read()9 print('%d bytes received from %s.' %(len(data), url))10

11 gevent.joinall([12 gevent.spawn(f, 'https://www.python.org/'),13 gevent.spawn(f, 'https://www.yahoo.com/'),14 gevent.spawn(f, 'https://github.com/'),15 ])

View Code

31>29>

python的进程线程和协程_python成长之路 :线程、进程和协程相关推荐

  1. python为什么会出现无响应怎么办_python定时检测无响应进程并重启的实例代码

    总有一些程序在windows平台表现不稳定,动不动一段时间就无响应,但又不得不用,每次都是发现问题了手动重启,现在写个脚本定时检测进程是否正常,自动重启. 涉及知识点 schedule定时任务调度 o ...

  2. python学会了可以做什么菜_python学习之路(24)

    访问限制 在Class内部,可以有属性和方法,而外部代码可以通过直接调用实例变量的方法来操作数据,这样,就隐藏了内部的复杂逻辑. 但是,从前面Student类的定义来看,外部代码还是可以自由地修改一个 ...

  3. python语言中最基本的概念_Python 学习之路-基本的概念(三)

    Python中一些经常用到的概念: 1.在Python中是没有常量的概念,换句话说在Python各种所有量都是可以更改的,规定将项定义为常量的量都定义为大写,eg:CONSTOF = "th ...

  4. python程序的控制结构思维导图_python学习之路2(程序的控制结构)

    1.程序的分支结构 1.1 单分支 if <条件>: 例:guess = eval(input()) <语句块> if guess == 99: print("猜对了 ...

  5. python命名规则数字开头的成语_python小白之路(基础知识一)

    一.开篇输出:print("Hello World!") 二.中文自由行:#coding=utf-8 或 # -- coding:UTF-8 -- 三.Linux多行:#!/usr ...

  6. python123.io作业_python成长之路-----day1-----作业(登录程序和三级菜单)

    作业: 作业1:用户登录 1)程序说明: a.用户输入密码验证成功然后打印欢迎信息 b.如果密码错误,用户登录失败,提示用户,密码错误 c.用户输入密码错误3次,则用户锁定 d.当用户多次输入不存在的 ...

  7. python协程和线程_python之并发编程(线程\进程\协程)

    一.进程和线程 1.进程 假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是 ...

  8. python apply_async死锁_python之并发编程(线程\进程\协程)

    一.进程和线程 1.进程假如有两个程序A和B,程序A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源.是不 ...

  9. python协程处理多个文件_python:多任务(线程、进程、协程)

    一.线程 1.创建线程 #创建线程 importthreading,timedeftask1():for i in range(5):print('task1 -- 任务:%s' %i) time.s ...

最新文章

  1. Numpy 生成 Bool型数组、一维转多维数组reshape、多维转一维数组、替换数组元素、提取数组元素、数组交集、差集、过滤数组元素、二维数组反转行、交换数组维度
  2. 新书上市 | 6岁的gRPC,终于出书了!
  3. VTK:可视化算法之CarotidFlow
  4. 用户退出登录清空cookie
  5. 【JSP笔记】第三章 JSP内置对象【上】
  6. 派生类类型可以转换为基类类型,反之则不行
  7. 注解@Cacheable(value =“XXX“) 实现缓存 -- 失效原因
  8. 华为交换机不同网段互访_华为交换机实现不同VLAN之间互访
  9. C#.NET验证码智能识别学习笔记---04C#.Net图片操作
  10. 请问这样写法,第二个container的内容怎么没有显示的呢?但是加上jumbotron就可以显示了,不明白。...
  11. 微信小程序云开发实现一对一聊天
  12. 鸟与虫(六)拉勾网,我可不可以找到工作
  13. daniel powter
  14. oracle判断不包含,oracle查询不含括号及不含指定字符的方法
  15. 对RGB三个通道进行操作示例
  16. OPPO手机设备安装谷歌服务套件GMS,使用Play商店
  17. 全新 Google Pixel Watch 重磅上线 | 着手为 Wear OS 构建应用!
  18. 7-12 两个数的简单计算器
  19. S3 #DooTrader 经典组冠军以良好盘感,创下近 900% 收益率摘得桂冠
  20. iomanip I/O流类库操纵符

热门文章

  1. Android 引用模块中的类,解决Android项目中找不到Module中的封装类或引用的第三方类库...
  2. linux ls-l getswd,liunx
  3. python中的iter()函数与next()函数
  4. 安利几个优质NLP开源项目!搜索、问答、情感分析…
  5. 论文浅尝 | 基于置信度的知识图谱表示学习框架
  6. 快速的找出元素是否在list中 python
  7. 50个数据可视化最有价值的图表(附完整Python代码,建议收藏
  8. 箱线图和散点图叠加图形的绘制——R language
  9. 【小程序】微信小程序开发实践
  10. 【Java】如何理解Java中的异常机制?