- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
假设我有几个脚本发送(合法!)电子邮件。每个脚本处理更大列表的一部分,并且它们同时运行。在发送之前,必须检查每个地址,以避免向同一个地址发送两次。
为此,我创建了一个仅包含电子邮件地址的简单表(mysql 5.1,innodb)。如果它不在表中,则添加它并发送邮件。现在我需要避免多个脚本同时测试同一个地址并错误地断定它没有被发送到的竞争条件。我想我可以为此使用锁,但出于性能原因我宁愿不这样做。
所以我想知道下面的选择是否正确:
在此设置中,是否仍有可能出现竞争条件?我的意思是:是否仍然有可能两个几乎同时插入地址的脚本都得出邮件未发送的结论?或者我应该为此使用锁?
谢谢,静
最佳答案
首先我觉得数据库不是最好的地方。当您的更大列表正在发送电子邮件时(由于您试图瘫痪,我猜测规模非常大)您必须使用临时表,因为您不想限制向收件人发送不同的电子邮件以前的邮件。
缓存是维护地址列表或充当共享内存资源的服务器的明显选择。
但是您可以在数据库中执行此操作,据我了解,如果一个电子邮件地址不止一次存在,这并不重要,因为您所做的只是检查过去是否曾发送过一个电子邮件地址。如果没有锁定策略,您无法真正控制多个脚本同时发送到同一地址的竞争条件。但是,您可以通过使用索引来提高效率。我不会索引实际地址,而是用地址的 CRC32 哈希创建一个新列(它可以是一个 32 位无符号整数,只占用 4 个字节的内存)。由于生日悖论,使用 CRC32 方法您还必须检查查询中的电子邮件地址。
例如:
SELECT COUNT(*) FROM email_addresses
WHERE email_address_crc = CRC32(?address)
AND email_address = ?address
拥有高效的东西应该有助于防止竞争条件,但是正如我之前所说,保证它的唯一方法是在发送每封电子邮件时锁定数据库,这样您就可以维护一个准确的列表——不幸的是,这不是t 规模,这意味着并行任务发送电子邮件可能无济于事。
编辑以回应以下评论:
正如评论中所指出的,我实际上忘记了解决 svdr 的锁定解决方案替代方案。确实,如果地址存在,包含电子邮件地址的唯一索引(或包含事件 ID 和地址的复合索引)确实会抛出 MySQL 异常,从而产生一个工作解决方案,将并行脚本发送到同一地址同时。但是,在脚本“尝试”发送电子邮件之前输入地址时,很难处理任何异常,例如由于 SMTP 错误/网络问题而无法发送电子邮件,这可能会导致收件人收不到电子邮件。还提供这是一个非常简单的 INSERT 和 SELECT,它应该可以捕获 MySQL 异常,但是如果有任何更复杂的东西,例如在事务中包装命令或使用 SELECT FOR UPDATE 等,这可能会导致死锁情况。
另一个考虑因素是,出于性能原因,电子邮件地址字段需要完全索引,如果使用 INNODB,则此限制为 767 字节 – 假设电子邮件地址的最大有效长度为 254(+1 字节长度,如果使用 VARCHAR)你应该没问题,只要你没有一些巨大的主键。
索引性能也应该得到解决,并且应该评估 CHAR 与 VCHAR。 CHAR 字段上的索引查找通常比等效的 VCHAR 查找快 15% - 25% – 固定宽度的表大小也有帮助,具体取决于所使用的表引擎。
总而言之,是的,你的非锁定解决方案可以工作,但应该根据你的具体要求仔细测试和评估(我无法评论具体细节,因为我认为你的现实生活场景比你的 SO 问题更复杂)。正如答案第一行所述,我仍然认为数据库不是最好的地方,缓存或共享内存空间会更有效,更容易实现。
关于mysql - 解决 INSERT race condition mysql,避免锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15155420/
我经常发现这些术语被用在并发编程的上下文中。它们是相同的还是不同的? 最佳答案 不,它们不是同一件事。它们不是彼此的子集。它们也不是彼此的必要条件,也不是充分条件。 数据竞争的定义非常明确,因此,它的
我在测试我的项目时遇到了 DATA RACE 警告,想知道是否有人愿意帮助我破译这个问题。我过去从未尝试过测试 go 例程,我发现很难全神贯注于数据竞赛。 我在描述中提供了指向未解决问题的链接,并在问
起初,我知道代码有一些竞争条件,所以我使用“go build -race”命令来检查它,我想看看结果如何显示,当我第一次运行时,它显示了第一个结果如下,然后再次运行显示第二个,它有两个不同的结果,我不
我在考虑我的代码中的极端情况,我不知道如何在检查文件是否存在时避免问题,如果不存在,则创建一个具有该文件名的文件。代码大致如下所示: // 1 status = stat(filename); if
我在考虑我的代码中的极端情况,我不知道如何在检查文件是否存在时避免问题,如果不存在,则创建一个具有该文件名的文件。代码大致如下所示: // 1 status = stat(filename); if
我想知道是否存在插入查询上实际发生竞争条件问题的真实案例。所以我有一个包含以下字段的“用户”表: User: iduser | idcompany | name | email 我为此表使用复合主键(
我有一段代码(一个测试运行器)应该运行代码并返回结果,我想为每个测试用例设置一个时间限制所以我使用 Promise.race 但不幸的是它不起作用 const createTestCafe = req
我遇到了 an implementation JavaScript 中的 Promise.race() 方法,它按预期工作,但对我来说意义不大。 const race = (...promises)
我的测试代码如下,使用threading,count不是5,000,000,所以出现data race,但是使用gevent,count是5,000,000,没有data race。 难道gevent
据我所知,关于promise有两个选项: promise.all() promise.race() 好的,我知道 promise.all() 是做什么的。它并行运行 Promise,如果两者都成功解析
又是我和我的BlockingQueue...我根据this article重写了它和 this question .它发送了一些项目,然后因访问冲突而崩溃。这是代码: template bool D
所以我有两个Python3.2进程需要相互通信。大多数需要交流的信息都是标准词典。命名管道似乎是可行的方法,所以我制作了一个可以在两个进程中实例化的管道类。这个类实现了一个非常基本的协议(protoc
我有一个注册页面,它接收 token 并解析它们并在参数适用时登录用户。 在我检查 token 的时间到我从数据库中删除 token 的时间之间,另一个用户可以使用相同的 token 登录。有没有办法
我在 redis 中有一个散列,其中一个字段的值为字符串化数组,每当用户注册一个事件时, 从redis中获取这个字符串化数组 后台解析,将用户的用户名添加到数组中 将数组字符串化并存储回哈希 如果两个
我知道之前有人问过这个问题,但我仍然很困惑,如果可能的话,我想在开始编程之前避免任何问题。 我计划拥有一个在任何给定时间至少有 100 名活跃用户的内部网站。用户将发布一个项目(以 0 作为其值插入到
我在面试中被问到以下问题。给定以下代码,如果方法 add 和 doAction 被多个线程调用,我们如何在打印 toString 时得到 NullPointerException ?** public
为什么标志“-race”的结果与预期的不一样?它期望相同的结果:1000000 - 带有标志“-race”但没有这个 https://gist.github.com/romanitalian/f403
我正在尝试了解如何为以下代码修复此竞争条件。 sayHello := func() { fmt.Println("Hello from goroutine") } go sayHello()
我有一堆 goroutines 在循环中做一些事情。我希望能够暂停所有这些,运行一些任意代码,然后恢复它们。我尝试这样做的方式可能不是惯用的(我希望有更好的解决方案),但我不明白为什么它不起作用。 精
考虑一个实现 open()、read()、write()、close()、unlocked_ioctl() 和 mmap() 的 linux 设备驱动程序。 现在,假设多个(或相同的)进程同时打开同一
我是一名优秀的程序员,十分优秀!