jjzjj

dictionary - golang线程安全映射, channel 作为线程安全的值

coder 2024-07-12 原文

我用 this作为并发映射,缓冲 channel 作为线程安全的映射值(作为队列工作),当测试使用 10 个 goroutines 时,从 channel 获得的值与发送的值不同,有什么建议吗?

package main

import "fmt"
import "github.com/streamrail/concurrent-map"

func main() {
    testmap := cmap.New()
    fmt.Println("SyncMapNew:    ", TestInParallel(&testmap, 10))
}

func TestInParallel(g *cmap.ConcurrentMap, n int) time.Duration {
    start := time.Now()
    var wait sync.WaitGroup

    for i := 0; i < n; i++ {
        wait.Add(1)
        go func() {
            TheTest(g, rand.New(rand.NewSource(int64(i*500))))
            wait.Done()
        }()
    }
    wait.Wait()
    return time.Now().Sub(start)
}

func TheTest(g *cmap.ConcurrentMap, rnd *rand.Rand) time.Duration {
    start := time.Now()
    var key string
    var value time.Time
    for i := 0; i < 10000; i++ {
        key = strconv.Itoa(int(rnd.Int31n(50000)))
        if g.Has(key) == false {
            g.Set(key, make(chan time.Time, 100))
        }
        tchan, _ := g.Get(key)
        castchan := tchan.(chan time.Time)
        value = time.Now()
        castchan <- value
        got := <-castchan
        g.Set(key, castchan)
        if value != got {
            panic(fmt.Sprintf("ERROR: expected %v, got %v", value, got))
        }
    }
    return time.Now().Sub(start)
}

更新我理解错了业务逻辑,代码应该是这样的

key = strconv.Itoa(int(rnd.Int31n(500)))
tchan, _ := g.GetSet(key, make(chan time.Time, 100))
castchan := tchan.(chan time.Time)
value = time.Now()
if len(castchan) >= 99 {
   <-castchan//do somthing here
}
castchan <- value
g.Set(key, castchan)

最佳答案

您使用的是随 secret 钥,因此多个 goroutine 可能会获得相同的随机数。

如果两个例程在同一时间获得相同的数字,则

这是一个竞争条件:

if g.Has(key) == false {
    g.Set(key, make(chan time.Time, 100))
}

有可能 h.Has 在同一时间对两个 goroutines 为 false 然后它们都设置了,所以 goroutine1 设置了 chan A,goroutine2 设置了 chan B,然后都使用了 chan B

为了解决这个问题,你需要类似的东西

SetIfAbsent

哪个锁,检查它是否存在,如果不存在,设置它,然后解锁。

您链接 map 的库作为缓存并不是非常有用,因为它不提供原子 SetIfAbsent 类型的函数。


如果没有 g.Has/g.Set 竞争,那么如果两个例程恰好获得相同的键,因此,相同的 channel ,您无法保证哪个值在队列中排在第一位,并且首先阅读。

所以 goroutine1 可能会读取 goroutine2 放入的值,反之亦然。

当考虑在并发执行系统中使用共享状态时,您必须假设任何其他操作都可能发生在任何语句/代码行之间。

我通常喜欢将其视为,您应该假设您的每一行代码一次在每个核心上运行。

因此,在 Has/Set 示例中它将是:

if g.Has(key) == false { // goroutine1
if g.Has(key) == false { // goroutine2
    g.Set(key, make(chan time.Time, 100)) //goroutine1
    g.Set(key, make(chan time.Time, 100)) //goroutine2 
} //goroutine1
} //goroutine2
tchan, _ := g.Get(key) //goroutine1
tchan, _ := g.Get(key) //goroutine2

看看错误在哪里?第二个例程将它的 channel 放在 map 中,但两者都在 tchan 线上检索到相同的 channel 。

有道理吗?

关于dictionary - golang线程安全映射, channel 作为线程安全的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30339066/

有关dictionary - golang线程安全映射, channel 作为线程安全的值的更多相关文章

  1. ruby - RSpec - 使用测试替身作为 block 参数 - 2

    我有一些Ruby代码,如下所示:Something.createdo|x|x.foo=barend我想编写一个测试,它使用double代替block参数x,这样我就可以调用:x_double.should_receive(:foo).with("whatever").这可能吗? 最佳答案 specify'something'dox=doublex.should_receive(:foo=).with("whatever")Something.should_receive(:create).and_yield(x)#callthere

  2. ruby - 如何使用 Ruby aws/s3 Gem 生成安全 URL 以从 s3 下载文件 - 2

    我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A

  3. ruby - 如果指定键的值在数组中相同,如何合并哈希 - 2

    我有一个这样的哈希数组:[{:foo=>2,:date=>Sat,01Sep2014},{:foo2=>2,:date=>Sat,02Sep2014},{:foo3=>3,:date=>Sat,01Sep2014},{:foo4=>4,:date=>Sat,03Sep2014},{:foo5=>5,:date=>Sat,02Sep2014}]如果:date相同,我想合并哈希值。我对上面数组的期望是:[{:foo=>2,:foo3=>3,:date=>Sat,01Sep2014},{:foo2=>2,:foo5=>5:date=>Sat,02Sep2014},{:foo4=>4,:dat

  4. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  5. ruby - 检查字符串是否包含散列中的任何键并返回它包含的键的值 - 2

    我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案

  6. ruby - 获取模块中定义的所有常量的值 - 2

    我想获取模块中定义的所有常量的值:moduleLettersA='apple'.freezeB='boy'.freezeendconstants给了我常量的名字:Letters.constants(false)#=>[:A,:B]如何获取它们的值的数组,即["apple","boy"]? 最佳答案 为了做到这一点,请使用mapLetters.constants(false).map&Letters.method(:const_get)这将返回["a","b"]第二种方式:Letters.constants(false).map{|c

  7. ruby - 字符串文字中的转义状态作为 `String#tr` 的参数 - 2

    对于作为String#tr参数的单引号字符串文字中反斜杠的转义状态,我觉得有些神秘。你能解释一下下面三个例子之间的对比吗?我特别不明白第二个。为了避免复杂化,我在这里使用了'd',在双引号中转义时不会改变含义("\d"="d")。'\\'.tr('\\','x')#=>"x"'\\'.tr('\\d','x')#=>"\\"'\\'.tr('\\\d','x')#=>"x" 最佳答案 在tr中转义tr的第一个参数非常类似于正则表达式中的括号字符分组。您可以在表达式的开头使用^来否定匹配(替换任何不匹配的内容)并使用例如a-f来匹配一

  8. ruby - 如何安全地删除文件? - 2

    在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?

  9. ruby - 如何让Ruby捕获线程中的语法错误 - 2

    我正在尝试使用ruby​​编写一个双线程客户端,一个线程从套接字读取数据并将其打印出来,另一个线程读取本地数据并将其发送到远程服务器。我发现的问题是Ruby似乎无法捕获线程内的错误,这是一个示例:#!/usr/bin/rubyThread.new{loop{$stdout.puts"hi"abc.putsefsleep1}}loop{sleep1}显然,如果我在线程外键入abc.putsef,代码将永远不会运行,因为Ruby将报告“undefinedvariableabc”。但是,如果它在一个线程内,则没有错误报告。我的问题是,如何让Ruby捕获这样的错误?或者至少,报告线程中的错误?

  10. ruby-on-rails - 应用程序的名称是否可以作为变量使用? - 2

    当我创建一个Rails应用程序时,控制台:railsnewfoo我的代码可以使用字符串“foo”吗?puts"Yourapp'snameis"+app_name_bar 最佳答案 Rails.application.class将为您提供应用程序的全名(例如YourAppName::Application)。从那里您可以使用Rails.application.class.parent获取模块名称。 关于ruby-on-rails-应用程序的名称是否可以作为变量使用?,我们在StackOve

随机推荐