Java教程

网络并发编程之线程

本文主要是介绍网络并发编程之线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

线程理论

  什么是线程

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

 

  线程的出现

    60年代,在OS中能拥有资源和独立运行的基本单位是进程,然而随着计算机技术的发展,进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)出现,可以满足多个运行单位,而多个进程并行开销过大。     因此在80年代,出现了能独立运行的基本单位——线程(Threads)     注意:进程是资源分配的最小单位,线程是CPU调度的最小单位。每一个进程中至少有一个线程。 

 

  进程与线程的关系 

    1.地址空间和其它资源(如打开文件):进程间相互独立,同一进程的各线程间共享。某进程内的线程在其它进程不可见。

    2.通信:进程间通信IPC,线程间可以直接读写进程数据段(如全局变量)来进行通信——需要进程同步和互斥手段的辅助,以保证数据的一致性。

    3.调度和切换:线程上下文切换比进程上下文切换要快得多。

    4.在多线程操作系统中,进程不是一个可执行的实体。

  线程的特点

    1.多线程共享一个进程的地址空间

    2.线程比进程更轻量级,线程比进程更容易创建可撤销,在许多操作系统中,创建一个线程比创建一个进程要快10-100倍,在有大量线程需要动态和快速修改时,这一特性很有用

    3.若多个线程都是cpu密集型的,那么并不能获得性能上的增强,但是如果存在大量的计算和大量的I/O处理,拥有多个线程允许这些活动彼此重叠运行,从而会加快程序执行的速度。

    4.在多cpu系统中,为了最大限度的利用多核,可以开启多个线程,比开进程开销要小的多。(这一条并不适用于python)

创建线程的两种方式

  方式一:

from threading import Thread
import time

def test(name):
    time.sleep(2)
    print('%s say hello' %name)

if __name__ == '__main__':
    t=Thread(target=test,args=('xie',))
    t.start()
    print('主线程')
函数方式

  方式二:

from threading import Thread
import time

class MyThread(Thread):
    def __init__(self,name):
        super().__init__()
        self.name=name

    def run(self):
        time.sleep(2)
        print('%s say hello' % self.name)


if __name__ == '__main__':
    t = MyThread('xie')
    t.start()
    print('主线程')
类方式

线程模块中的其他方法

  t.isAlive(): 返回线程是否活动的

  t.getName(): 返回线程名

  t.setName(): 设置线程名

  threading.currentThread(): 返回当前的线程变量

  threading.enumerate(): 返回一个包含正在运行的线程的list。正在运行指线程启动后、结束前,不包括启动前和终止后的线程

  threading.activeCount(): 返回正在运行的线程数量,与len(threading.enumerate())有相同的结果

 

守护线程

  随主线程运行完毕而停止并被回收。对主线程来说,运行完毕指的是主线程所在的进程内所有非守护线程统统运行完毕,主线程才算运行完毕。

from threading import Thread
import time

def foo():
    print(123)
    time.sleep(1)
    print("end123")

def bar():
    print(456)
    time.sleep(3)
    print("end456")


t1=Thread(target=foo)
t2=Thread(target=bar)

t1.daemon=True
t1.start()
t2.start()
print("main-------")
# 输出依次:
# 123
# 456
# main-------
# end123
# end456
守护线程

互斥锁

  模拟100个人同时抢票的情况,在不加锁的情况下数据容易混乱的,就很有可能造成最后的数据与逻辑不符。

from threading import Thread
import time

def grab():
    global n
    temp=n
    time.sleep(0.1)
    n=temp-1
if __name__ == '__main__':
    n=100
    l=[]
    for i in range(100):
        t=Thread(target=grab)
        l.append(p)
        t.start()
    for t in l:
        t.join()

    print(n) #结果可能为99
错误现象

  我们需要加锁保证数据的安全,即把并行改成串行,保证同一时间内只有一个线程执行对数据的操作。threading与multiprocess类似,也有Lock。

from threading import Thread,Lock
import time

def grab():
    global n
    lock.acquire()
    temp=n
    time.sleep(0.1)
    n=temp-1
    lock.release()
if __name__ == '__main__':
    lock=Lock()
    n=100
    l=[]
    for i in range(100):
        t=Thread(target=grab)
        l.append(t)
        t.start()
    for t in l:
        t.join()

    print(n)  # 结果肯定为0,由原来的并发执行变成串行,牺牲了执行效率保证了数据安全
加锁

TCP服务端实现并发

  只要在服务端开设多线程来接收多个客户端的访问就能实现并发

import socket
from threading import Thread
from multiprocessing import Process

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)


def talk(sock):
    while True:
        try:
            data = sock.recv(1024)
            if len(data) == 0: break
            print(data.decode('utf8'))
            sock.send(data + b'server端')
        except ConnectionResetError as e:
            print(e)
            break
    sock.close()


while True:
    sock, addr = server.accept()
    print(addr)
    # 开设多进程或者多线程
    t = Thread(target=talk, args=(sock,))
    t.start()
server端并发

 

这篇关于网络并发编程之线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!