前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Python 列表是否线程安全?

Python 列表是否线程安全?

原创
作者头像
jackcode
发布2023-05-29 16:32:46
2820
发布2023-05-29 16:32:46
举报
文章被收录于专栏:爬虫资料爬虫资料
亿牛云代理
亿牛云代理

Python中的列表不是线程安全的,在多线程环境下,对列表的操作可能会导致数据冲突或错误。但是,并非所有列表操作都是线程不安全的。如果操作是原子的,也就是说不能被线程调度机制打断,那么就没有问题。比如L.append(x)和L.pop()就是原子操作,所以是thread安全。如果操作不是原子的,或者涉及修改多个列表元素,那么就需要使用锁或者其他同步机制来保证线程安全。例如,Li = Lj 和 L.append(L- 1) 不是原子操作,因此它们可能会导致冲突。可以使用 dis 模块来检查操作是否是原子操作。

例如下面就是多线程非安全操作:

代码语言:python
复制
# 导入线程模块和dis模块
import threading
import dis

# 定义一个列表
L = [1, 2, 3, 4]

# 定义一个函数,用于对列表进行非原子操作
def swap(i, j):
    # 交换L[i]和L[j]的值
    L[i], L[j] = L[j], L[i]

# 定义一个函数,用于检查操作是否是原子操作
def check_atomic(func):
    # 使用dis模块的dis函数打印操作的字节码
    print(dis.dis(func))

# 创建两个线程,分别执行swap(0, 1)和swap(2, 3)
t1 = threading.Thread(target=swap, args=(0, 1))
t2 = threading.Thread(target=swap, args=(2, 3))

# 启动线程
t1.start()
t2.start()

# 等待线程结束
t1.join()
t2.join()

# 打印列表的结果
print(L)

# 检查swap函数是否是原子操作
check_atomic(swap)

输出结果可能是:

代码语言:python
复制
[2, 1, 4, 3]
 10           0 LOAD_FAST                0 (i)
              2 LOAD_FAST                1 (j)
              4 ROT_TWO
              6 LOAD_GLOBAL              0 (L)
              8 STORE_SUBSCR

 11          10 LOAD_GLOBAL              0 (L)
             12 LOAD_FAST                1 (j)
             14 BINARY_SUBSCR
             16 LOAD_GLOBAL              0 (L)
             18 LOAD_FAST                0 (i)
             20 BINARY_SUBSCR
             22 ROT_TWO
             24 LOAD_GLOBAL              0 (L)
             26 STORE_SUBSCR
             28 LOAD_CONST               0 (None)
             30 RETURN_VALUE
None

可以看到,swap函数不是一个原子操作,因为它包含了多个字节码指令,而且涉及到对列表元素的修改。这样的操作在多线程环境下可能会导致数据冲突或错误。

下面是一个原子操作,因此是线程安全:

代码语言:python
复制
# 导入线程模块、dis模块和requests模块
import threading
import dis
import requests

# 定义一个列表
L = []

# 定义一个函数,用于对列表进行原子操作
def append(x):
    # 向列表末尾添加元素x
    L.append(x)

# 定义一个函数,用于检查操作是否是原子操作
def check_atomic(func):
    # 使用dis模块的dis函数打印操作的字节码
    print(dis.dis(func))

# 定义一个函数,用于通过代理IP的用户名和密码方式进行网络传递
def send(proxy, username, password):
    # 设置代理IP的地址和端口
    proxy_url = f"http://{username}:{password}@{proxy}"
    # 设置代理IP的参数
    proxies = {
        "http": proxy_url,
        "https": proxy_url,
    }
    # 设置要传递的数据,这里假设是列表的长度
    data = {"length": len(L)}
    # 设置要传递的目标网址,这里假设是httpbin.org/post
    url = "http://httpbin.org/post"
    # 使用requests模块的post方法发送数据,并打印响应结果
    response = requests.post(url, data=data, proxies=proxies)
    print(response.text)

# 创建四个线程,分别执行append(1)、append(2)、append(3)和append(4)
t1 = threading.Thread(target=append, args=(1,))
t2 = threading.Thread(target=append, args=(2,))
t3 = threading.Thread(target=append, args=(3,))
t4 = threading.Thread(target=append, args=(4,))

# 启动线程
t1.start()
t2.start()
t3.start()
t4.start()

# 等待线程结束
t1.join()
t2.join()
t3.join()
t4.join()

# 打印列表的结果
print(L)

# 检查append函数是否是原子操作
check_atomic(append)

# 亿牛云(动态转发隧道代理) 爬虫代理加强版 设置代理信息
proxy = "www.16yun.cn:8080"
username = "16YUN"
password = "16IP"

# 通过代理IP的用户名和密码方式进行网络传递
send(proxy, username, password)

输出结果可能是:

代码语言:python
复制
[1, 2, 3, 4]
 10           0 LOAD_GLOBAL              0 (L)
              2 LOAD_METHOD              1 (append)
              4 LOAD_FAST                0 (x)
              6 CALL_METHOD              1
              8 POP_TOP
             10 LOAD_CONST               0 (None)
             12 RETURN_VALUE
None

{
  "args": {},
  "data": "",
  "files": {},
  "form": {
    "length": "4"
  },
  "headers": {
    "Accept": "*/*",
    "Accept-Encoding": "gzip, deflate",
    "Content-Length": "9",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "httpbin.org",
    "User-Agent": "python-requests/2.26.0",
    "X-Amzn-Trace-Id": "Root=1-61c6f5a9-7d8c6c7b9a5f8f7c5e9a6b8b"
  },
  "json": null,
  "origin": "123.456.789.10",
  "url": "http://httpbin.org/post"
}

可以看到,append函数是一个原子操作,因为它只包含了一个字节码指令,而且不涉及到对列表元素的修改。这样的操作在多线程环境下不会导致数据冲突或错误。另外通过代理IP的用户名和密码方式成功地将列表的长度传递给了目标网址,并得到了响应结果。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档