検索
ホームページバックエンド開発GolangGo言語でのGoroutineの使い方を詳しく解説

Go言語でのGoroutineの使い方を詳しく解説

Nov 25, 2019 pm 02:34 PM
言語を移動

Go言語でのGoroutineの使い方を詳しく解説

go の goroutine は、言語レベルで同時実行性をサポートする go language の機能です。初めて Go に触れたとき、Go の goroutine に非常に満足しました。並行性の実装はばかばかしいほど簡単です。

しかし、プロジェクトのプロセス中に、Goroutine は誰でも簡単に悪用できるものであることがますますわかりました。ゴルーチンは両刃の剣です。 goroutine を使用することの罪は次のとおりです:

1. goroutine で渡すポインタは安全ではありません

fun main() {
    request := request.NewRequest() //这里的NewRequest()是传递回一个type Request的指针
    go saveRequestToRedis1(request)
    go saveReuqestToRedis2(request)
     
    select{}
 
}

非常に論理的なコード :

メイン ルーチンは、リクエストを saveRequestToRedis1 に渡すルーチンを開き、リクエストを Redis ノード 1 に保存できるようにします。

同時に、別のルーチンを開いてリクエストを saveReuqestToRedis2 に渡します。リクエストを保存できます。redis ノード 2 に移動します。

その後、メイン ルーチンが (プロセスを終了せずに) ループに入ります。

ここで問題が発生します。saveRequestToRedis1 と saveReuqestToRedis2 の 2 つの関数は、実際には存在しませんでした。誰かが書いたものですが、その実装については何も知りませんし、特定の内部実装を詳しく調べたくありません。しかし、関数名に従って、それを当然のこととして、リクエスト ポインタを渡しました。

実際、saveRequestToRedis1 と saveRequestToRedis2 は次のように実装されています。

func saveRequestToRedis1(request *Request){
     …
     request.ToUsers = []int{1,2,3} //这里是一个赋值操作,修改了request指向的数据结构
     …
    redis.Save(request)
    return
}

これの何が問題なのでしょうか? 2 つのゴルーチン saveRequestToRedis1 と saveReuqestToRedis2 は同じ共有データ構造を変更しますが、ルーチンの実行には順序がないため、request.ToUsers 設定と redis.Save() がアトミックな操作であることは保証できません。データエラーバグが発生します。

そうですね、この saveRequestToRedis 関数の実装には問題があり、go ルーチンを使用して呼び出されるということは考慮されていなかったと言えます。 saveRequestToRedis の具体的な実装は問題ありませんが、上位層での使用方法は考慮しないでください。

それは、私の goroutine の使用に問題があるためです。メイン ルーチンがルーチンを開くとき、ルーチン内のコードがメイン ルーチンのデータを変更したかどうかは確認されません。はい、メインルーチンはこの状況を考慮する必要があります。

メインのゴルーチンが go ルーチンを有効にすると、サブルーチン内のコードの各行を読み取って、共有データが変更されたかどうかを判断する必要があります。 ?実際のプロジェクト開発プロセスでは、これがどれほど開発スピードを遅らせることになるでしょうか。

Go 言語は同時開発のプレッシャーを軽減するために goroutine を使用していますが、それが逆に開発のプレッシャーを高めることになるとは考えていませんでした。

上記では多くのことを述べてきましたが、結論としては次のとおりです:

gotine ポインタの受け渡しは安全ではありません。 !

前の例が十分にわかりにくい場合は、別の例を示します:

fun (this *Request)SaveRedis() {
    redis1 := redis.NewRedisAddr("xxxxxx")
    redis2 := redis.NewRedisAddr("xxxxxx")
    go this.saveRequestToRedis(redis1)
    go this.saveRequestToRedis(redis2)
     
    select{}
}

このポインターが指すオブジェクトに問題があるかどうかを考える人はほとんどいないでしょう。ここでの this ポインターは次のとおりです。ルーチンに渡されます。これは非常に隠蔽されていると言うべきです。

2. Goroutine は関数の危険因子を増加させます

この点は、実際には上記の点から派生しています。上で述べたように、Go 関数にポインターを渡すのは安全ではありません。では、別の角度から考えてみましょう。呼び出したい関数が関数実装内で使用されないことをどのように保証できるでしょうか?関数本体内の特定の実装を見ない限り、それを判断する方法はありません。

たとえば、上記の典型的な例を少し変更すれば、

func main() {
    request := request.NewRequest()
    saveRequestToRedis1(request)
    saveRequestToRedis2(request)
    select{}
}

同時実行性を使用していないので、この問題は絶対に発生しませんよね。私は関数を追いかけましたが、唖然としました。

func saveReqeustToRedis1(request *Request) {
           …
            go func() {
          …
          request.ToUsers = []{1,2,3}
         ….
         redis.Save(request)
    }
}

ゴルーチンが内部で開始され、リクエスト ポインタが指すオブジェクトを変更しました。ここでエラーが発生しました。まあ、関数を呼び出すときに関数内の特定の実装を見ない限り、この問題は回避できません。

つまり、最悪の観点から見ると、すべての関数呼び出しは理論的には安全ではありません。想像してみてください。この呼び出し関数が私自身の開発チームの誰かによって書かれたのではなく、インターネット上のサードパーティのオープン ソース コードを使用していたとしたら...このバグを見つけるのにどれくらいの時間がかかるか、本当に想像できません。

3. Goroutine 悪用トラップ

この例を見てください:

func main() {
    go saveRequestToRedises(request)
}
 
func saveRequestToRedieses(request *Request) {
    for _, redis := range Redises {
        go redis.saveRequestToRedis(request)
    }
}
 
func saveRequestToRedis(request *Request) {
            ….
            go func() {
                     request.ToUsers = []{1,2,3}
                        …
                        redis.Save(request)
            }
 
}

すごいですね、go はどこにでもあるようです瞬きする間にどこからともなく現れること。これは go の乱用です。go はどこにでもありますが、あまり明確ではありません。どこで go を使用すればよいでしょうか?なぜ go を使うのでしょうか? goroutine は本当に効率を向上させるのでしょうか?

C 言語の同時実行は Go 言語の同時実行よりもはるかに複雑で面倒なので、使用する前によく考え、同時実行を使用するメリットとデメリットを検討します。

処理方法

これらの問題に対処するための私の方法をいくつか紹介します:

1.開始ゴルーチンを使用する場合、関数がポインタを渡す必要があるが、関数レベルが非常に深く安全性が保証できない場合は、ポインタを直接渡すのではなく、オブジェクトのクローンにポインタを渡します

fun main() {
    request := request.NewRequest()
    go saveRequestToRedis1(request.Clone())
    go saveReuqestToRedis2(request.Clone())
     
    select{}
 
}

Clone関数は別途記述する必要があります。構造を定義した後は、この方法に簡単に従うことができます。例えば:###

func (this *Request)Clone(){
    newRequest := NewRequst()
    newRequest.ToUsers = make([]int, len(this.ToUsers))
    copy(newRequest.ToUsers, this.ToUsers)
 
}

其实从效率角度考虑这样确实会产生不必要的Clone的操作,耗费一定内存和CPU。但是在我看来,首先,为了安全性,这个尝试是值得的。

其次,如果项目对效率确实有很高的要求,那么你不妨在开发阶段遵照这个原则使用clone,然后在项目优化阶段,作为一种优化手段,将不必要的Clone操作去掉。这样就能在保证安全的前提下做到最好的优化。

2、什么时候使用go的问题

有两种思维逻辑会想到使用goroutine:

1 业务逻辑需要并发

比如一个服务器,接收请求,阻塞式的方法是一个请求处理完成后,才开始第二个请求的处理。其实在设计的时候我们一定不会这么做,我们会在一开始就已经想到使用并发来处理这个场景,每个请求启动一个goroutine为它服务,这样就达到了并行的效果。这种goroutine直接按照思维的逻辑来使用goroutine

2 性能优化需要并发

一个场景是这样:需要给一批用户发送消息,正常逻辑会使用

for _, user := range users {
    sendMessage(user)
 
}

但是在考虑到性能问题的时候,我们就不会这样做,如果users的个数很大,比如有1000万个用户?我们就没必要将1000万个用户放在一个routine中运行处理,考虑将1000万用户分成1000份,每份开一个goroutine,一个goroutine分发1万个用户,这样在效率上会提升很多。这种是性能优化上对goroutine的需求

按照项目开发的流程角度来看。在项目开发阶段,第一种思路的代码实现会直接影响到后续的开发实现,因此在项目开发阶段应该马上实现。

但是第二种,项目中是由很多小角落是可以使用goroutine进行优化的,但是如果在开发阶段对每个优化策略都考虑到,那一定会直接打乱你的开发思路,会让你的开发周期延长,而且很容易埋下潜在的不安全代码。

因此第二种情况在开发阶段绝不应该直接使用goroutine,而该在项目优化阶段以优化的思路对项目进行重构。

推荐:golang开发栏目

以上がGo言語でのGoroutineの使い方を詳しく解説の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事は博客园で複製されています。侵害がある場合は、admin@php.cn までご連絡ください。
GOインターフェイスでアサーションとタイプスイッチを入力しますGOインターフェイスでアサーションとタイプスイッチを入力しますMay 02, 2025 am 12:20 AM

gohandlesinterfacesandtypeassertionseffectivivivivivity、強化された柔軟性と耐毒性を強化します

エラーを使用し、エラーを使用して、goでエラー検査を行いますエラーを使用し、エラーを使用して、goでエラー検査を行いますMay 02, 2025 am 12:11 AM

言語エラー処理は、エラーとエラーを介してより柔軟になり、読みやすくなります。 1.エラーは、エラーが指定されたエラーと同じであり、エラーチェーンの処理に適しているかどうかを確認するために使用されます。 2.エラー。エラータイプを確認するだけでなく、エラーを特定のタイプに変換することもできます。これは、エラー情報を抽出するのに便利です。これらの関数を使用すると、エラー処理ロジックを簡素化できますが、エラーチェーンの正しい配信に注意を払い、コードの複雑さを防ぐために過度の依存性を回避できます。

GOのパフォーマンスチューニング:アプリケーションの最適化GOのパフォーマンスチューニング:アプリケーションの最適化May 02, 2025 am 12:06 AM

tomakegogoapplicationsRunfasterAndMore -efficient、useprofilingtools、leverageconconcurrency、andmanagememoryefcectively.1)useprofforcpuandmemoryprofilingtoidentififybottlenecks.2)

GOの未来:トレンドと開発GOの未来:トレンドと開発May 02, 2025 am 12:01 AM

go'sfutureisbrightwithtrendslikeRikeRovedTooling、generics、cloud-nativeadoption、performulenhancements、andwebassemblyintegration、butchallengesincludemaintainingsimplicitandimplovingeror handling。

Goroutinesの理解:Goの同時性に深く潜りますGoroutinesの理解:Goの同時性に深く潜りますMay 01, 2025 am 12:18 AM

GoroutinesAreSareSareSareSormethodSthaturncurlyntingo、Enableing and LightweightConcurrency.1)theyRuntimeSimeSingMultiplexing、SountyStorunonFeweroSthReads.2)ゴルチンズを失ったことを許可します

go:目的と使用法でのinit機能を理解するgo:目的と使用法でのinit機能を理解するMay 01, 2025 am 12:16 AM

initistoistoInitializevariables、setupconutupurations、orforformndexedarysetupbe foreThemainfunctionexecutes.useinitby:1)inginginyourcodeTorunautorunaintalunain、2)KeepingItshortandpocusedonsimpletasks、3)ConsididiriveSusinginsingingingingingingingingingingingingingingingingingingingingingingsingpltassksを使用すると、

GOインターフェイスの理解:包括的なガイドGOインターフェイスの理解:包括的なガイドMay 01, 2025 am 12:13 AM

go interfacesaremethodsignaturesetsetsattypesmustimplement、unableingpolymorphism withintinheritance forcleaner、modularcode.theyareimplictilistifisisfiestified、houseforfflexibleapisanddeaupling、busrecarefulusoavoidoidoimoidimeerrororsypertety。

GOのパニックからの回復:いつ、どのように使用するか()GOのパニックからの回復:いつ、どのように使用するか()May 01, 2025 am 12:04 AM

Goで回復()関数を使用して、パニックから回復します。特定の方法は次のとおりです。1)回復()を使用して、延期関数でパニックをキャプチャして、プログラムのクラッシュを避けます。 2)デバッグの詳細なエラー情報を記録します。 3)特定の状況に基づいてプログラムの実行を再開するかどうかを決定します。 4)パフォーマンスに影響を及ぼさないように注意して使用します。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

SecLists

SecLists

SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

Dreamweaver Mac版

Dreamweaver Mac版

ビジュアル Web 開発ツール